diff --git a/package-lock.json b/package-lock.json index ca1c11c..b0e9308 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "acryl-blockchain-explorer", - "version": "2.0.1", + "version": "2.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/App.js b/src/App.js index 9e2a6b8..922a319 100644 --- a/src/App.js +++ b/src/App.js @@ -5,18 +5,18 @@ import {Route, Switch} from 'react-router'; import {BrowserRouter as Router} from 'react-router-dom'; import ScrollToTop from 'react-scroll-up'; -import {routeParams, routes} from './shared/Routing'; -import Search from './Search'; -import Header from './Header'; -import NavBar from './NavBar'; -import MainPage from './main/MainPage'; -import PeersPage from './peers/PeersPage'; -import NodesPage from './nodes/NodesPage'; -import BlocksPage from './blocks/BlocksPage'; -import SingleBlockPage from './blocks/SingleBlockPage'; -import SingleTransactionPage from './transactions/SingleTransactionPage'; -import SingleAddressPage from './addresses/SingleAddressPage'; -import SingleAliasPage from './aliases/SingleAliasPage'; +import {routeParams, routes} from './components/shared/Routing'; +import Search from './components/Search/Search'; +import Header from './components/Header/Header'; +import NavBar from './components/NavBar/NavBar'; +import MainPage from './pages/main/MainPage'; +import PeersPage from './pages/peers/PeersPage'; +import NodesPage from './pages/nodes/NodesPage'; +import BlocksPage from './pages/blocks/BlocksPage'; +import SingleBlockPage from './pages/blocks/SingleBlockPage'; +import SingleTransactionPage from './pages/transactions/SingleTransactionPage'; +import SingleAddressPage from './pages/addresses/SingleAddressPage'; +import SingleAliasPage from './pages/aliases/SingleAliasPage'; class App extends React.Component { state = { diff --git a/src/Footer.js b/src/Footer.js deleted file mode 100644 index 2896885..0000000 --- a/src/Footer.js +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; - -const socialLinks = [{ - id: 'github', - url: 'https://github.com/acrylplatform' -}, { - id: 'twitter', - url: 'https://twitter.com/acrylplatform' -}, { - id: 'facebook', - url: 'https://www.facebook.com/acrylplatformofficial' -}, { - id: 'discord', - url: '#' -}, { - id: 'telegram', - url: 'https://t.me/Acrylplatform' -}, { - id: 'reddit', - url: '#' -}]; - -const Footer = ({version}) => { - return ( -
-
Version: {version}
-
Brought to you by Acryl Team
-
- {socialLinks.map(item => - ())} -
-
- acrylplatform.com -
-
- ); -} - -export default Footer; diff --git a/src/Header.js b/src/Header.js deleted file mode 100644 index 7daeeb3..0000000 --- a/src/Header.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const Header = (props) => { - return ( -
-
-
props.onMenuToggle()}> - -
-
-
- {props.children} -
- ); -}; - -Header.propTypes = { - onMenuToggle: PropTypes.func.isRequired -}; - -export default Header; diff --git a/src/NavBar.js b/src/NavBar.js deleted file mode 100644 index 15fbe03..0000000 --- a/src/NavBar.js +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import NavMenu from './NavMenu'; -import Footer from './Footer'; -import NetworkSwitch from './NetworkSwitch'; - -import ServiceFactory from './services/ServiceFactory'; - -const REGULAR_APPEARANCE = 'regular'; - -const reloadWindow = () => window.location.reload(); - -class NavBar extends React.Component { - static propTypes = { - appearance: PropTypes.string, - onAfterNavigate: PropTypes.func - }; - - static defaultProps = { - appearance: REGULAR_APPEARANCE, - onAfterNavigate: () => {} - }; - - switchNetwork = networkId => { - ServiceFactory.configurationService().select(networkId); - - reloadWindow(); - }; - - applySettings = settings => { - ServiceFactory.configurationService().update(settings); - this.forceUpdate(); - reloadWindow(); - }; - - render() { - const configurationService = ServiceFactory.configurationService(); - - let className = 'menu grid-item-fixed'; - if (this.props.appearance === REGULAR_APPEARANCE) - className += ' lg-hide'; - - const version = __VERSION__ || '0'; - - return ( -
- - -
- ); - } -} - -export default NavBar; diff --git a/src/NavMenu.js b/src/NavMenu.js deleted file mode 100644 index 392794e..0000000 --- a/src/NavMenu.js +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {withRouter} from 'react-router'; - -import {routes} from './shared/Routing'; -import NavMenuItem from './NavMenuItem'; - -const items = [{ - title: 'General info', - route: routes.root, - icon: 'icon-general' -}, { - title: 'Blocks', - route: routes.blocks.list, - icon: 'icon-blocks' -}, { - title: 'Peers', - route: routes.peers.list, - icon: 'icon-peers' -}, { - title: 'Nodes', - route: routes.nodes.list, - icon: 'icon-nodes' -}]; - -class NavMenu extends React.Component { - static propTypes = { - onAfterNavigate: PropTypes.func.isRequired - }; - - constructor(props) { - super(props); - - const {pathname} = this.props.location; - - this.state = { - items, - current: items.find(item => item.route === pathname) || items[0] - }; - } - - handleNavigate = item => { - this.setState({ - current: item - }); - - this.props.onAfterNavigate(); - }; - - render() { - return ( -
- {this.state.items.map((item, index) => { - const current = this.state.current === item; - return ( - - ); - })} -
- ); - } -} - -export default withRouter(NavMenu); diff --git a/src/NavMenuItem.js b/src/NavMenuItem.js deleted file mode 100644 index b2e5010..0000000 --- a/src/NavMenuItem.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Link} from 'react-router-dom'; - -export default class NavMenuItem extends React.PureComponent { - static propTypes = { - item: PropTypes.object.isRequired, - current: PropTypes.bool, - onNavigate: PropTypes.func.isRequired - }; - - static defaultProps = { - current: false - }; - - handleClick = () => { - this.props.onNavigate(this.props.item); - }; - - render() { - let className = `menu-item ${this.props.item.icon}`; - if (this.props.current) - className += ' current'; - - return ( -
- {this.props.item.title} -
- ); - } -} diff --git a/src/NetworkSwitch.js b/src/NetworkSwitch.js deleted file mode 100644 index 368e847..0000000 --- a/src/NetworkSwitch.js +++ /dev/null @@ -1,98 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import Modal from 'react-modal'; - -import ConfigurationForm from './ConfigurationForm'; - -const Network = ({networkId, displayName, onSwitchNetwork}) => { - return
onSwitchNetwork(networkId)}>{displayName}
; -}; - -const extractEditableConfiguration = configuration => ( - (({apiBaseUrl}) => ({apiBaseUrl}))(configuration) -); - -const NetworkShape = PropTypes.shape({ - networkId: PropTypes.string, - displayName: PropTypes.string, - url: PropTypes.string, - apiBaseUrl: PropTypes.string, - spamListUrl: PropTypes.string -}); - -export default class NetworkSwitch extends React.PureComponent { - static propTypes = { - current: NetworkShape.isRequired, - networks: PropTypes.arrayOf(NetworkShape).isRequired, - custom: NetworkShape, - onSwitchNetwork: PropTypes.func, - onUpdateCustomNetwork: PropTypes.func - }; - - static defaultProps = { - onSwitchNetwork: () => {}, - onUpdateCustomNetwork: () => {} - }; - - state = { - showNetworks: false, - showModal: false - }; - - toggleModal = () => { - this.setState({showModal: !this.state.showModal}); - }; - - toggleNetworks = () => { - this.setState({showNetworks: !this.state.showNetworks}); - }; - - switchNetwork = (networkId) => { - this.setState({showNetworks: false}); - - this.props.onSwitchNetwork(networkId); - }; - - render() { - const {current, networks} = this.props; - const listClassName = 'network-list' + (this.state.showNetworks ? ' expanded' : ''); - - const custom = this.props.custom || { - apiBaseUrl: '' - }; - const configuration = extractEditableConfiguration(custom); - - return ( -
-
-
- - {current.displayName} -
- {networks - .filter(item => item.networkId !== current.networkId) - .map((item, index) => { - return - }) - } -
-
-
-
- - - -
- ); - } -} diff --git a/src/Search.js b/src/Search.js deleted file mode 100644 index bbe2bfa..0000000 --- a/src/Search.js +++ /dev/null @@ -1,121 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {withRouter} from 'react-router'; - -import ServiceFactory from './services/ServiceFactory'; - -const FADE_TIMEOUT = 2000; - -class Search extends React.PureComponent { - constructor(props) { - super(props); - - this.state = { - isLoading: false, - isFocused: false, - isFailed: false, - searchText: '' - }; - this.inputRef = React.createRef(); - } - - go = (route) => { - this.props.history.push(route); - }; - - handleKeyUp = (e) => { - if (e.key === 'Enter') { - this.setState({ - isFailed: false, - isLoading: true - }); - - const searchService = ServiceFactory.searchService(); - - return searchService.search(this.state.searchText).then(route => { - this.setState({ - searchText: '', - isLoading: false - }); - - this.go(route); - }).catch(err => { - console.error(err); - - this.setState({ - isLoading: false, - isFailed: true - }); - - setTimeout(() => this.setState({isFailed: false}), FADE_TIMEOUT); - }); - } - }; - - handleChange = (e) => { - this.setState({ - searchText: e.target.value, - isFailed: false - }); - }; - - handleFocus = (e) => { - this.setState({isFocused: true}); - }; - - handleBlur = (e) => { - this.setState({isFocused: false}); - }; - - handleClearClick = () => { - this.setState({searchText: ''}); - - this.inputRef.current.focus(); - }; - - render() { - const textIsNotEmpty = !!this.state.searchText; - - let className = 'search-box grid grid-center'; - if (this.state.isFailed) { - className += ' search-box-invalid'; - } - - if (this.state.isFocused) { - className += ' search-box-focus'; - } else if (textIsNotEmpty) { - className += ' search-box-active'; - } - - if (this.state.isLoading) { - className += ' search-box-loading'; - } - - return ( -
-
- - - - -
- - {textIsNotEmpty &&
- - - - Clear
} -
- ); - } -} - -export default withRouter(Search); diff --git a/src/addresses/Address.js b/src/addresses/Address.js deleted file mode 100644 index 23f8d0a..0000000 --- a/src/addresses/Address.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {withRouter} from 'react-router'; - -import EndpointRef from '../shared/EndpointRef'; - -class Address extends React.PureComponent { - static propTypes = { - address: PropTypes.string, - }; - - render() { - const currentAddress = this.props.match.params.address; - const {address} = this.props; - - if (!address) - return null; - - if (address === currentAddress) - return ; - - return ; - } -} - -export default withRouter(Address); diff --git a/src/addresses/AssetList.js b/src/addresses/AssetList.js deleted file mode 100644 index ed50a7e..0000000 --- a/src/addresses/AssetList.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import AssetListItem from './AssetListItem'; - -export default class AssetList extends React.Component { - static propTypes = { - assets: PropTypes.arrayOf(PropTypes.object).isRequired - }; - - render() { - return ( - - - - - - - - - - {this.props.assets.map((asset, index) => { - return (); - })} - -
IDNameBalance
- ); - } -} diff --git a/src/addresses/AssetListItem.js b/src/addresses/AssetListItem.js deleted file mode 100644 index 945c83b..0000000 --- a/src/addresses/AssetListItem.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import TransactionRef from '../shared/TransactionRef'; - -export default class AssetListItem extends React.PureComponent { - static propTypes = { - asset: PropTypes.object.isRequired - }; - - render() { - const {asset} = this.props; - return ( - - -
- - -
{asset.name}
- - -
{asset.amount}
- - - ); - } -} diff --git a/src/addresses/BalanceDetails.js b/src/addresses/BalanceDetails.js deleted file mode 100644 index 69d8106..0000000 --- a/src/addresses/BalanceDetails.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const BalanceDetails = ({balance}) => { - return ( -
-
-
-
{balance.regular}
-
-
-
-
{balance.generating}
-
-
-
-
{balance.available}
-
-
-
-
{balance.effective}
-
-
- ); -}; - -BalanceDetails.propTypes = { - balance: PropTypes.shape({ - regular: PropTypes.string, - generating: PropTypes.string, - available: PropTypes.string, - effective: PropTypes.string - }) -}; -export default BalanceDetails; diff --git a/src/addresses/GroupedAliasList.js b/src/addresses/GroupedAliasList.js deleted file mode 100644 index 095fca7..0000000 --- a/src/addresses/GroupedAliasList.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import GroupedAliasListItem from './GroupedAliasListItem'; -import NoData from '../shared/NoData'; - -export default class GroupedAliasList extends React.Component { - static propTypes = { - aliases: PropTypes.arrayOf(PropTypes.object).isRequired - }; - - render() { - return ( - - - - - - - - - - {this.props.aliases.map((aliasGroup, index) => { - return (); - })} - -
Alias
- {this.props.aliases.length === 0 && } -
- ); - } -} diff --git a/src/addresses/GroupedAliasListItem.js b/src/addresses/GroupedAliasListItem.js deleted file mode 100644 index e83789e..0000000 --- a/src/addresses/GroupedAliasListItem.js +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const AliasLine = (props) => { - return ( -
-
{props.alias}
-
- ); -}; - -AliasLine.propTypes = { - alias: PropTypes.string.isRequired -}; - -export default class GroupedAliasListItem extends React.PureComponent { - static propTypes = { - aliasGroup: PropTypes.object.isRequired - }; - - render() { - const group = this.props.aliasGroup; - - return ( - - -
- {group.letter} -
- - -
- {group.aliases.map((alias, index) => { - return (); - })} -
- - - ); - } -} diff --git a/src/addresses/Pane.js b/src/addresses/Pane.js deleted file mode 100644 index 29c9817..0000000 --- a/src/addresses/Pane.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const Pane = props => { - return props.children; -}; - -Pane.propTypes = { - title: PropTypes.string.isRequired -}; - -export default Pane; diff --git a/src/addresses/SingleAddressPage.js b/src/addresses/SingleAddressPage.js deleted file mode 100644 index c1b2fbf..0000000 --- a/src/addresses/SingleAddressPage.js +++ /dev/null @@ -1,125 +0,0 @@ -import React from 'react'; - -import GoBack from '../shared/GoBack'; -import Headline from '../shared/Headline'; -import Loader from '../shared/Loader'; -import ServiceFactory from '../services/ServiceFactory'; - -import TransactionList from './TransactionList'; -import AssetList from './AssetList'; -import GroupedAliasList from './GroupedAliasList'; -import DataInfo from '../shared/DataInfo'; -import ScriptInfo from '../shared/ScriptInfo'; -import Tabs from './Tabs'; -import Pane from './Pane'; -import BalanceDetails from './BalanceDetails'; -import transactionMapper from './TransactionMapper'; - -export default class SingleAddressPage extends React.Component { - state = { - balance: {}, - assets: [], - aliases: [], - transactions: [], - data: [], - script: {}, - selectedTabIndex: 0 - }; - - componentDidUpdate(prevProps) { - if (this.props.match.params.address !== prevProps.match.params.address) { - this.fetchData(); - } - } - - setAcryl(str) { - return str.includes('WAVES') ? str.replace('WAVES', 'ACRYL') : str; - } - - fetchData = () => { - const { address } = this.props.match.params; - const addressService = ServiceFactory.addressService(); - - return addressService.loadBalance(address) - .then(balance => { - - for (const item in balance) { - balance[item] = this.setAcryl(balance[item]); - } - return this.setState({ balance }) - }) - .then(_ => this.fetchTabData(this.state.selectedTabIndex)); - }; - - fetchTabData = (selectedIndex) => { - const { address } = this.props.match.params; - const addressService = ServiceFactory.addressService(); - - switch (selectedIndex) { - case 0: - return addressService.loadTransactions(address).then(transactions => { - return transactionMapper(transactions, address); - }) - .then(transactions => { - for (const transaction of transactions) { - if(transaction.out) { - transaction.out.currency = this.setAcryl(transaction.out.currency); - } - if(transaction.in) { - transaction.in.currency = this.setAcryl(transaction.in.currency); - } - - } - this.setState({ transactions }); - }); - - case 1: - return addressService.loadAliases(address).then(aliases => this.setState({ aliases })); - - case 2: - return addressService.loadAssets(address).then(assets => this.setState({ assets })); - - case 3: - return addressService.loadData(address).then(data => this.setState({ data })); - - case 4: - return addressService.loadScript(address).then(script => this.setState({ script })); - } - - return Promise.resolve(); - }; - - handleTabActivate = (selectedIndex) => { - this.fetchTabData(selectedIndex); - this.setState({ selectedTabIndex: selectedIndex }); - }; - - render() { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - ); - } -} diff --git a/src/addresses/Tabs.js b/src/addresses/Tabs.js deleted file mode 100644 index b9b6a9b..0000000 --- a/src/addresses/Tabs.js +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -class TabHeader extends React.PureComponent { - static propTypes = { - isActive: PropTypes.bool.isRequired, - title: PropTypes.string.isRequired, - index: PropTypes.number.isRequired, - onActivate: PropTypes.func.isRequired - }; - - handleClick = (e) => { - e.preventDefault(); - - this.props.onActivate(this.props.index); - }; - - render() { - let className = 'page-link bold'; - if (this.props.isActive) - className += ' disabled'; - - return ( - - {this.props.isActive ? - this.props.title : - {this.props.title}} - - ); - } -} - -export default class Tabs extends React.Component { - static propTypes = { - selectedIndex: PropTypes.number, - onTabActivate: PropTypes.func.isRequired - }; - - static defaultProps = { - selectedIndex: 0 - }; - - handleTabActivate = (selectedIndex) => { - this.props.onTabActivate(selectedIndex); - }; - - render() { - const {selectedIndex} = this.props; - - return ( - -
- {this.props.children.map((child, index) => { - return - })} -
- {this.props.children[selectedIndex]} -
- ); - } -} diff --git a/src/addresses/TransactionList.js b/src/addresses/TransactionList.js deleted file mode 100644 index a9525f5..0000000 --- a/src/addresses/TransactionList.js +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import InfiniteScroll from 'react-infinite-scroller'; - -import ServiceFactory from '../services/ServiceFactory'; -import TransactionListItem from './TransactionListItem'; -import transactionMapper from './TransactionMapper'; -import Loading from '../shared/Loading'; - -export default class TransactionList extends React.Component { - state = { - hasMore: true, - } - - static propTypes = { - transactions: PropTypes.arrayOf(PropTypes.object).isRequired - }; - - componentWillMount() { - let status = this.props.transactions.length >= 100 ? true : false; - this.setState({ hasMore: status }); - } - - setAcryl(str) { - return str.replace('WAVES', 'ACRYL'); - } - - loadMore() { - const addressService = ServiceFactory.addressService(); - const address = this.props.address; - let arrTransactions = this.props.transactions; - let after = arrTransactions[arrTransactions.length-1].id; - - addressService.loadTransactions(address, 100, after).then(transactions => { - return transactionMapper(transactions, address); - }) - .then(transactions => { - if (transactions.length < 100) { this.state.hasMore = false } - for (const transaction of transactions) { - if(transaction.out) { - transaction.out.currency = this.setAcryl(transaction.out.currency); - } - if(transaction.in) { - transaction.in.currency = this.setAcryl(transaction.in.currency); - } - arrTransactions.push(transaction) - } - this.setState({ transactions: arrTransactions }); - }); - } - - render() { - return ( - } - > - - - - - - - - - - - - {this.props.transactions.map((tx, index) => { - return (); - })} - -
ID / TypeTimestampSender / ReceiverAmount in / outPrice
-
- ); - } -} diff --git a/src/addresses/TransactionListItem.js b/src/addresses/TransactionListItem.js deleted file mode 100644 index 6eb9b88..0000000 --- a/src/addresses/TransactionListItem.js +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import Address from './Address'; -import TransactionRef from '../shared/TransactionRef'; -import {TransactionDirections} from '../shared/TransactionDefinitions'; -import TransactionArrow from '../shared/TransactionArrow'; -import TransactionBadge from '../shared/TransactionBadge'; - -const Endpoints = ({direction, sender, recipient}) => { - if (direction === TransactionDirections.OUTGOING) { - return ( - -
{recipient ?
: '\u00A0'}
-
-
- ); - } - - return ( - -
-
-
- ); -}; - -export default class TransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - const rowClassName = tx.isSpam ? 'spam' : ''; - - return ( - - -
-
- - -
-
- - - - - - - {tx.in &&
{tx.in.amount} {tx.in.currency}
} - {tx.out &&
{tx.out.amount} {tx.out.currency}
} - - - {tx.price && -
{tx.price.amount}
-
-
} - - - ); - } -} diff --git a/src/addresses/TransactionMapper.js b/src/addresses/TransactionMapper.js deleted file mode 100644 index 95a39da..0000000 --- a/src/addresses/TransactionMapper.js +++ /dev/null @@ -1,153 +0,0 @@ -import Money from '../shared/Money'; - -// consider extracting to a module -const INCOMING = 'incoming'; -const OUTGOING = 'outgoing'; - -const transactionMapper = (transactions, currentAddress) => { - return transactions.map(item => mapTransactionToPromise(item, currentAddress)); -}; - -const mapTransactionToPromise = (tx, currentAddress) => { - switch (tx.type) { - case 2: - case 4: - return mapTransfer(tx, currentAddress); - - case 3: - return mapIssue(tx, currentAddress); - - case 5: - return mapReissue(tx, currentAddress); - - case 6: - return mapBurn(tx, currentAddress); - - case 7: - return mapExchange(tx, currentAddress); - - case 8: - return mapLease(tx, currentAddress); - - case 9: - return mapLeaseCancel(tx, currentAddress); - - case 10: - return mapAlias(tx, currentAddress); - - case 11: - return mapMassTransfer(tx, currentAddress); - - default: - return Object.assign({}, tx); - } -}; - -const copyMandatoryAttributes = tx => ({ - id: tx.id, - type: tx.type, - timestamp: tx.timestamp, - sender: tx.sender, - isSpam: tx.isSpam -}); - -const defaultDirection = (tx, currentAddress) => { - return tx.sender === currentAddress ? OUTGOING : null; -}; - -const moneyToObject = money => ({ - amount: money.formatAmount(true), - currency: money.currency.toString() -}); - -const mapMassTransfer = (tx, currentAddress) => { - const tail = {}; - if (tx.sender === currentAddress) { - tail.direction = OUTGOING; - tail.out = moneyToObject(tx.totalAmount); - } else { - tail.direction = INCOMING; - tail.recipient = currentAddress; - - let total = new Money(0, tx.totalAmount.currency); - tx.transfers.filter(transfer => transfer.recipient === currentAddress).forEach(t => { - total = total.plus(t.amount); - }); - - tail.in = moneyToObject(total); - } - - return Object.assign(copyMandatoryAttributes(tx), tail); -}; - -const mapAlias = (tx, currentAddress) => { - return Object.assign(copyMandatoryAttributes(tx), { - direction: defaultDirection(tx, currentAddress) - }); -}; - -const mapLease = (tx, currentAddress) => { - return Object.assign(copyMandatoryAttributes(tx), { - direction: defaultDirection(tx, currentAddress), - recipient: tx.recipient, - out: moneyToObject(tx.amount) - }); -}; - -const mapLeaseCancel = (tx, currentAddress) => { - return Object.assign(copyMandatoryAttributes(tx), { - direction: defaultDirection(tx, currentAddress), - recipient: tx.recipient - }); -}; - -const mapExchange = (tx, currentAddress) => { - return Object.assign(copyMandatoryAttributes(tx), { - sender: tx.sender, - recipient: tx.recipient, - in: moneyToObject(tx.total), - out: moneyToObject(tx.amount), - price: { - amount: tx.price.toTokens().toFixed(8), - currency: tx.buyOrder.assetPair.priceAsset.toString() - } - }); -}; - -const mapBurn = (tx, currentAddress) => { - return Object.assign(copyMandatoryAttributes(tx), { - direction: defaultDirection(tx, currentAddress), - out: moneyToObject(tx.amount) - }); -}; - -const mapReissue = (tx, currentAddress) => { - return Object.assign(copyMandatoryAttributes(tx), { - direction: defaultDirection(tx, currentAddress), - out: moneyToObject(tx.amount) - }); -}; - -const mapIssue = (tx, currentAddress) => { - return Object.assign(copyMandatoryAttributes(tx), { - direction: defaultDirection(tx, currentAddress), - out: moneyToObject(tx.amount) - }); -}; - -const mapTransfer = (tx, currentAddress) => { - const tail = {recipient: tx.recipient}; - const money = moneyToObject(tx.amount); - - if (tx.recipient === currentAddress) { - tail.direction = INCOMING; - tail.in = money; - } else { - tail.direction = OUTGOING; - tail.out = money; - } - - return Object.assign(copyMandatoryAttributes(tx), tail); -}; - -export default transactionMapper; diff --git a/src/aliases/SingleAliasPage.js b/src/aliases/SingleAliasPage.js deleted file mode 100644 index ddbfed5..0000000 --- a/src/aliases/SingleAliasPage.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import {Redirect} from 'react-router-dom'; - -import {routes} from '../shared/Routing'; -import ServiceFactory from '../services/ServiceFactory'; - -import Loader from '../shared/Loader'; - -export default class SingleAliasPage extends React.Component { - state = { - address: null - }; - - fetchData = () => { - return ServiceFactory.aliasService() - .loadAddress(this.props.match.params.alias) - .then(address => this.setState({address})) - }; - - render() { - return ( - - {this.state.address && } - - ); - } -} diff --git a/src/blocks/BlockEnumerator.js b/src/blocks/BlockEnumerator.js deleted file mode 100644 index f64252c..0000000 --- a/src/blocks/BlockEnumerator.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export default class BlockEnumerator extends React.PureComponent { - static propTypes = { - height: PropTypes.number.isRequired, - hasPrev: PropTypes.bool, - hasNext: PropTypes.bool, - disabled: PropTypes.bool, - onNext: PropTypes.func, - onPrev: PropTypes.func - }; - - static defaultProps = { - hasPrev: true, - hasNext: true, - disabled: false, - onNext: () => {}, - onPrev: () => {} - }; - - handleClickPrev = () => { - if (this.props.disabled) - return; - - if (this.props.hasPrev) - this.props.onPrev(); - }; - - handleClickNext = () => { - if (this.props.disabled) - return; - - if (this.props.hasNext) - this.props.onNext(); - }; - - render() { - const prevClass = "btn btn-prev" + (this.props.hasPrev && !this.props.disabled ? "" : " disabled"); - const nextClass = "btn btn-next" + (this.props.hasNext && !this.props.disabled ? "" : " disabled"); - return ( - - - {this.props.height} - - - ); - } -} diff --git a/src/blocks/BlockList.js b/src/blocks/BlockList.js deleted file mode 100644 index 7cd9b4f..0000000 --- a/src/blocks/BlockList.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import BlockListItem from './BlockListItem'; - -export default class BlockList extends React.Component { - static propTypes = { - blocks: PropTypes.arrayOf(PropTypes.object).isRequired - }; - - render() { - return ( - - - - - - - - - - - {this.props.blocks.map((block, index) => { - return (); - })} - -
№ / TimestampBase TargetGenerator / SignatureTXs
- ); - } -} diff --git a/src/blocks/BlockListItem.js b/src/blocks/BlockListItem.js deleted file mode 100644 index 77c7977..0000000 --- a/src/blocks/BlockListItem.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import EndpointRef from '../shared/EndpointRef'; -import BlockRef from '../shared/BlockRef'; - -export default class BlockListItem extends React.Component { - static propTypes = { - block: PropTypes.object.isRequired - }; - - render() { - const {block} = this.props; - const rowClassName = block.transactions > 0 ? '' : 'empty-block'; - - return ( - - -
-
-
- - -
{block.baseTarget}
- - -
-
- - -
{block.transactions}
- - - ); - } -} diff --git a/src/blocks/BlocksPage.js b/src/blocks/BlocksPage.js deleted file mode 100644 index b800535..0000000 --- a/src/blocks/BlocksPage.js +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; - -import Loader from '../shared/Loader'; -import ServiceFactory from '../services/ServiceFactory'; - -import Pagination from './Pagination'; -import BlockList from './BlockList'; - -const BLOCKS_PER_PAGE = 20; - -export default class BlocksPage extends React.Component { - state = { - height: 0, - currentPage: 1, - lastPage: 10, - blocks: [], - hasError: false - }; - - initialFetch = () => { - return ServiceFactory.infoService().loadHeight().then(height => { - const lastPage = Math.ceil(height / BLOCKS_PER_PAGE); - - this.setState({height, lastPage}); - - return this.loadCurrentPage(1); - }) - }; - - loadCurrentPage = (pageNumber) => { - const from = Math.max(1, this.state.height - pageNumber * BLOCKS_PER_PAGE + 1); - const to = Math.min(this.state.height, from + BLOCKS_PER_PAGE); - - ServiceFactory.blockService().loadSequence(from, to).then(blocks => this.setState({blocks})); - }; - - handlePageChange = pageNumber => { - this.loadCurrentPage(pageNumber); - }; - - render() { - return ( - - -
- Blocks - -
- -
-
- ); - } -} diff --git a/src/blocks/Pagination.js b/src/blocks/Pagination.js deleted file mode 100644 index 212be46..0000000 --- a/src/blocks/Pagination.js +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const NUMBER_OF_PAGES_IN_ROW = 5; - -const PageLimit = ({className, title, disabled, pageNumber, onPageChange}) => { - const linkClassName = className + (disabled ? ' disabled' : ''); - - return ( - onPageChange(pageNumber)}>{title} - ); -}; - -const PageLink = (props) => { - const visible = (typeof props.visible === 'undefined') ? true : props.visible; - if (!visible) - return (null); - - const title = props.title || props.pageNumber.toString(); - const className = 'page' + (props.current ? ' current' : ''); - - return ( props.onPageChange(props.pageNumber)}>{title}); -}; - -const derivePageBoundaries = (pageNumber, lastPage) => { - const lowPage = Math.floor((pageNumber - 1) / NUMBER_OF_PAGES_IN_ROW) * NUMBER_OF_PAGES_IN_ROW; - - return { - lowPage: lowPage + 1, - highPage: Math.min(lastPage, lowPage + NUMBER_OF_PAGES_IN_ROW) - }; -}; - -export default class Pagination extends React.PureComponent { - static propTypes = { - currentPage: PropTypes.number, - lastPage: PropTypes.number.isRequired, - onPageChange: PropTypes.func.isRequired - }; - - static defaultProps = { - currentPage: 1, - }; - - constructor(props) { - super(props); - - const boundaries = derivePageBoundaries(this.props.currentPage, this.props.lastPage); - this.state = { - currentPage: this.props.currentPage, - ...boundaries - }; - } - - handlePageChange = (pageNumber) => { - const boundaries = derivePageBoundaries(pageNumber, this.props.lastPage); - this.setState({ - currentPage: pageNumber, - ...boundaries - }); - - this.props.onPageChange(pageNumber); - }; - - render() { - const pageNumbers = []; - for (let i = this.state.lowPage; i <= this.state.highPage; i++) { - pageNumbers.push(i); - } - - return ( -
- - 1}/> - {pageNumbers.map(number => { - return (); - })} - - -
- ); - } -} diff --git a/src/blocks/SingleBlockPage.js b/src/blocks/SingleBlockPage.js deleted file mode 100644 index 83e439f..0000000 --- a/src/blocks/SingleBlockPage.js +++ /dev/null @@ -1,159 +0,0 @@ -import React from 'react'; - -import {routes} from '../shared/Routing'; -import GoBack from '../shared/GoBack'; -import EndpointRef from '../shared/EndpointRef'; -import Headline from '../shared/Headline'; -import CopyButton from '../shared/CopyButton'; -import Dictionary from '../shared/Dictionary'; -import Loader from '../shared/Loader'; - -import ServiceFactory from '../services/ServiceFactory'; - -import BlockEnumerator from './BlockEnumerator'; -import TransactionList from './TransactionList'; - -const typeToHeader = type => { - let result = { - id: 'ID / Timestamp', - subjects: 'Sender / Recipient', - amount: 'Amount / Fee', - price: 'Price' - }; - - switch (type) { - case 3: - result.subjects = 'Issuer / Asset ID'; - result.amount = 'Quantity / Fee'; - result.price = 'Asset name'; - break; - - case 4: - case 11: - result.price = 'Asset'; - break; - - case 7: - result.subjects = 'Seller / Buyer'; - result.amount = 'Amount / Total'; - result.price = 'Pair / Price'; - break; - - case 8: - result.price = undefined; - break; - - case 9: - result.price = undefined; - result.amount = 'Fee'; - break; - - case 10: - result.amount = 'Fee'; - break; - } - - return result; -}; - -export default class SingleBlockPage extends React.Component { - state = { - currentHeight: parseInt(this.props.match.params.height), - maxHeight: parseInt(this.props.match.params.height) + 1, - block: { - timestamp: {}, - generator: '' - }, - groupedTransactions: {}, - loading: false - }; - - componentDidUpdate(prevProps) { - if (this.props.match.params.height !== prevProps.match.params.height) { - const height = parseInt(this.props.match.params.height); - this.setState({currentHeight: height}); - this.fetchData(height) - .catch(error => { - console.error(error); - console.log("Error response status: " + error.status); - console.log(error.response.data); - }); - } - } - - initialFetch = () => { - return this.fetchData(this.state.currentHeight); - }; - - fetchData = height => { - this.setState({loading: true}); - - return ServiceFactory.blockService().loadBlock(height) - .then(result => this.setState(result)) - .then(() => this.setState({loading: false})); - }; - - showBlock = height => { - this.props.history.push(routes.blocks.one(height)); - }; - - render() { - const dictionaryItems = this.stateToDictionaryItems(); - return ( - - - - - - - {Object.keys(this.state.groupedTransactions).map(type => { - const numericType = parseInt(type); - const header = typeToHeader(numericType); - return - })} - - - ); - } - - stateToDictionaryItems() { - const items = [{ - label: 'Height', - value: ( - 1} - hasNext={this.state.currentHeight < this.state.maxHeight} - onNext={() => this.showBlock(this.state.currentHeight + 1)} - onPrev={() => this.showBlock(this.state.currentHeight - 1)}/> - ) - }, { - label: 'Version', - value: this.state.block.version - }, { - label: 'Timestamp', - value: {this.state.block.timestamp.time}, {this.state.block.timestamp.date} - }, { - label: 'Transactions', - value: this.state.block.transactionCount - }, { - label: 'Parent block', - value: this.state.block.reference, - action: - }, { - label: 'Generator', - value: - }, { - label: 'Signature', - value: this.state.block.signature, - action: - }, { - label: 'Size', - value: {this.state.block.blocksize} bytes - }]; - - return items; - } -} diff --git a/src/blocks/TransactionList.js b/src/blocks/TransactionList.js deleted file mode 100644 index 09e0ac5..0000000 --- a/src/blocks/TransactionList.js +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import {typeToTitle} from '../shared/TransactionDefinitions'; -import {createListItem} from './TransactionListItem'; - -export default class TransactionList extends React.Component { - static propTypes = { - type: PropTypes.number.isRequired, - header: PropTypes.shape({ - id: PropTypes.string, - subjects: PropTypes.string, - amount: PropTypes.string, - price: PropTypes.string - }), - transactions: PropTypes.arrayOf(PropTypes.object) - }; - - state = { - collapsed: false - }; - - handleClick = () => { - const collapsed = !this.state.collapsed; - this.setState({collapsed}); - }; - - render() { - const actionTitle = this.state.collapsed ? 'Show list' : 'Hide list'; - let tableClass = 'table-sm-transform'; - if (this.state.collapsed) { - tableClass += ' table-hide'; - } - - return ( - -
- {typeToTitle(this.props.type)} - — Type {this.props.type} - {actionTitle} -
- - - - - - - - - - - {this.props.transactions.map(item => { - return createListItem(item); - })} - -
{this.props.header.id}{this.props.header.subjects}{this.props.header.amount}{this.props.header.price}
-
- ); - } -} diff --git a/src/blocks/TransactionListItem.js b/src/blocks/TransactionListItem.js deleted file mode 100644 index 1874241..0000000 --- a/src/blocks/TransactionListItem.js +++ /dev/null @@ -1,368 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import DateTime from '../shared/DateTime'; -import EndpointRef from '../shared/EndpointRef'; -import CurrencyRef from '../shared/CurrencyRef'; -import TransactionRef from '../shared/TransactionRef'; -import TransactionArrow from '../shared/TransactionArrow'; -import Currency from '../shared/Currency'; - -export const createListItem = (transaction) => { - switch (transaction.type) { - case 2: - case 4: - return ; - - case 3: - case 5: - return ; - - case 6: - return ; - - case 7: - return ; - - case 8: - return ; - - case 9: - return ; - - case 10: - return ; - - case 11: - return ; - - case 12: - return ; - - case 13: - return ; - - case 14: - return ; - - default: - return null; - } -}; - -class Line extends React.PureComponent { - static propTypes = { - wrap: PropTypes.bool, - bold: PropTypes.bool - }; - - static defaultProps = { - wrap: true, - bold: false - }; - - render() { - let className = 'line'; - if (!this.props.wrap) - className += ' no-wrap'; - if (this.props.bold) - className += ' bold'; - - return
{this.props.children}
- } -} - -class IdAndTimestamp extends React.PureComponent { - static propTypes = { - id: PropTypes.string.isRequired, - timestamp: PropTypes.instanceOf(DateTime).isRequired - }; - - render() { - return ( - - - - - ); - } -} - -class Subjects extends React.PureComponent { - static propTypes = { - type: PropTypes.number.isRequired, - sender: PropTypes.string.isRequired, - recipient: PropTypes.string - }; - - render() { - return ( - - - - - {this.props.recipient && } - - - ); - } -} - -class AmountAndFee extends React.PureComponent { - static propTypes = { - amount: PropTypes.object, - fee: PropTypes.object - }; - - render() { - return ( - - {this.props.amount.toString()} - - - ); - } -} - -class JustFee extends React.PureComponent { - static propTypes = { - fee: PropTypes.object - }; - - render() { - return ( - - {this.props.fee.toString()} - - - ); - } -} - -class TransferTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - const rowClassName = tx.isSpam ? 'spam' : ''; - - return ( - - - - - - - - - ); - } -} - -class ExchangeTransactionListItem extends React.PureComponent { - render() { - const {tx} = this.props; - return ( - - - -
-
-
- - -
{tx.amount.toString()}
-
{tx.total.toString()}
- - -
- / -
-
{tx.price.toString()}
- - - ); - } -} - -class LeasingTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - return ( - - - - - - ); - } -} - -class CancelLeasingTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - return ( - - - - - - ); - } -} - -class IssueTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - return ( - - - - - - - - - - - - {tx.name} - - - ); - } -} - -class BurnTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - return ( - - - - - - - - - ); - } -} - -class AliasTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - return ( - - - - - - {tx.alias} - - - ); - } -} - -class MassPaymentTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - const rowClassName = tx.isSpam ? 'spam' : ''; - - return ( - - - - - - {tx.transferCount} - - - - - - - ); - } -} - -class DataTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - return ( - - - - - - ); - } -} - -class ScriptTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - return ( - - - - - - ); - } -} - -class SponsorshipTransactionListItem extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - return ( - - - - - - {tx.sponsoredFee && {tx.sponsoredFee.toString()}} - - - ); - } -} diff --git a/src/main/LastBlockList.js b/src/main/LastBlockList.js deleted file mode 100644 index 2aebdc3..0000000 --- a/src/main/LastBlockList.js +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Link} from 'react-router-dom'; - -import {routes} from '../shared/Routing'; -import LastBlockListItem from './LastBlockListItem'; -import Loader from '../shared/Loader'; - -import ServiceFactory from '../services/ServiceFactory'; - -const LAST_BLOCKS_COUNT = 20; - -export class LastBlockList extends React.PureComponent { - static propTypes = { - blocks: PropTypes.arrayOf(PropTypes.object).isRequired, - title: PropTypes.string - }; - - static defaultProps = { - title: 'Last blocks' - }; - - render() { - return ( -
-
- {this.props.title} - - View all blocks - -
- {this.props.blocks.map((block) => { - return (); - })} -
- ); - } -} - -export default class LastBlockListContainer extends React.Component { - state = { - blocks: [] - }; - - componentWillUnmount() { - this.removeRefreshInterval(); - } - - initialFetch = () => { - return this.fetchData().then(this.setRefreshInterval); - }; - - fetchData = () => { - return ServiceFactory.infoService().loadHeight() - .then(height => { - const to = height; - const from = Math.max(1, to - LAST_BLOCKS_COUNT); - return ServiceFactory.blockService().loadSequence(from, to) - }).then(blocks => this.setState({blocks})); - }; - - setRefreshInterval = () => { - this.interval = setInterval(() => this.fetchData(), 5000); - }; - - removeRefreshInterval = () => { - if (this.interval) { - clearInterval(this.interval); - this.interval = null; - } - }; - - render() { - return ( - - - - ); - } -} diff --git a/src/main/LastBlockListItem.js b/src/main/LastBlockListItem.js deleted file mode 100644 index fabcb2c..0000000 --- a/src/main/LastBlockListItem.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import BlockRef from '../shared/BlockRef'; - -export default class LastBlockListItem extends React.PureComponent { - static propTypes = { - block: PropTypes.object.isRequired - }; - - render() { - const block = this.props.block; - const emptyClassName = block.transactions > 0 ? '' : ' empty-block'; - const rowClassName = 'grid panel-row block-img-handler' + emptyClassName; - - return ( -
-
-
-
Block contains {block.transactions} transactions
-
-
-
-
-
-
-
-
- ); - } -} diff --git a/src/main/MainPage.js b/src/main/MainPage.js deleted file mode 100644 index 6b5269f..0000000 --- a/src/main/MainPage.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; - -import NetworkInfo from './NetworkInfo'; -import LastBlockList from './LastBlockList'; -import UnconfirmedTxList from './UnconfirmedTxList'; - -export default class MainPage extends React.Component { - render() { - return ( - -
- -
-
-
- -
-
- -
-
-
- ); - } -} diff --git a/src/main/NetworkInfo.js b/src/main/NetworkInfo.js deleted file mode 100644 index 7452dab..0000000 --- a/src/main/NetworkInfo.js +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import ServiceFactory from '../services/ServiceFactory'; - -import Loader from '../shared/Loader'; - -export class NetworkInfo extends React.PureComponent { - static propTypes = { - info: PropTypes.object.isRequired - }; - render() { - return ( -
- {Object.entries(this.props.info).map(entry => { - return (
-
-
{entry[1]}
-
); - })} -
- ); - } -} - -export default class NetworkInfoContainer extends React.Component { - state = { - info: {} - }; - - componentWillUnmount() { - this.removeRefreshInterval(); - } - - initialFetch = () => { - return this.fetchData().then(this.setRefreshInterval); - }; - - fetchData = () => { - const infoService = ServiceFactory.infoService(); - return infoService.loadInfo().then(info => { - info.Version = info.Version.includes('Waves') ? info.Version.replace('Waves', 'Acryl') : info.Version; - const change = Object.assign({}, this.state.info, info); - this.setState({ info: change }); - - infoService.loadDelay(info).then(info => this.setState({ info })); - }); - }; - - setRefreshInterval = () => { - this.interval = setInterval(() => this.fetchData(), 5000); - }; - - removeRefreshInterval = () => { - if (this.interval) { - clearInterval(this.interval); - this.interval = null; - } - }; - - render() { - return ( - - - - ); - } -} diff --git a/src/main/UnconfirmedTxList.js b/src/main/UnconfirmedTxList.js deleted file mode 100644 index 777fc04..0000000 --- a/src/main/UnconfirmedTxList.js +++ /dev/null @@ -1,103 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import Loader from '../shared/Loader'; -import UnconfirmedTxListItem from './UnconfirmedTxListItem'; - -import ServiceFactory from '../services/ServiceFactory'; - -export class UnconfirmedTxList extends React.Component { - static propTypes = { - transactions: PropTypes.arrayOf(PropTypes.object).isRequired - }; - - renderList() { - return ( - -
- Unconfirmed Transactions ({this.props.transactions.length}) -
- {this.props.transactions.map((item) => { - return (); - })} -
- ); - } - - renderEmpty() { - return ( - -
-
-
- ); - } - - render() { - const isEmpty = this.props.transactions.length === 0; - let wrapperClassName = 'panel'; - if (isEmpty) - wrapperClassName += ' panel-empty confirmed'; - - return ( -
- {isEmpty ? this.renderEmpty() : this.renderList()} -
- ); - } -} - -export default class UnconfirmedTxListContainer extends React.Component { - state = { - unconfirmed: [] - }; - - componentWillUnmount() { - this.removeRefreshInterval(); - } - - initialFetch = () => { - return this.fetchData().then(this.setRefreshInterval); - }; - - setAcryl = str => { - if(str.includes('WAVES') ) { - return str.replace('WAVES', 'ACRYL'); - } else if (str.includes('Waves') ) { - return str.replace('Waves', 'Acryl'); - } else { - return str; - } - } - - fetchData = () => { - return ServiceFactory.transactionService().loadUnconfirmed() - .then(unconfirmed => { - console.log('unconfirmed :', unconfirmed); - for (const unconfirmedTx of unconfirmed) { - unconfirmedTx.fee.currency.shortName = this.setAcryl(unconfirmedTx.fee.currency.shortName); - unconfirmedTx.fee.currency.displayName = this.setAcryl(unconfirmedTx.fee.currency.displayName); - } - this.setState({unconfirmed}) - }); - }; - - setRefreshInterval = () => { - this.interval = setInterval(() => this.fetchData(), 5000); - }; - - removeRefreshInterval = () => { - if (this.interval) { - clearInterval(this.interval); - this.interval = null; - } - }; - - render() { - return ( - - - - ); - } -} diff --git a/src/main/UnconfirmedTxListItem.js b/src/main/UnconfirmedTxListItem.js deleted file mode 100644 index dffc773..0000000 --- a/src/main/UnconfirmedTxListItem.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import EndpointRef from '../shared/EndpointRef'; - -export default class UnconfirmedTxListItem extends React.PureComponent { - static propTypes = { - transaction: PropTypes.object.isRequired - }; - - render() { - const tx = this.props.transaction; - return ( -
-
-
-
{tx.id}
-
- {tx.amount ? tx.amount.toString() : ''} -
- -
-
- -
- {tx.recipient && } -
-
-
-
-
-
-
-
-
- ); - } -} diff --git a/src/nodes/NodeListItem.js b/src/nodes/NodeListItem.js deleted file mode 100644 index 4fe5bb7..0000000 --- a/src/nodes/NodeListItem.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export default class NodeListItem extends React.Component { - static propTypes = { - node: PropTypes.object.isRequired - }; - - render() { - const {node} = this.props; - node.version = node.version.includes('Waves') ? node.version.replace('Waves', 'Acryl') : node.version; - return ( - - - - - -
{node.version}
- - -
{node.height}
- - -
{node.baseTarget}
- - -
{node.unconfirmedTxCount}
- - -
{node.maintainer}
- - - ); - } -} diff --git a/src/nodes/NodesPage.js b/src/nodes/NodesPage.js deleted file mode 100644 index 7fdb785..0000000 --- a/src/nodes/NodesPage.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import ServiceFactory from '../services/ServiceFactory'; -import Loader from '../shared/Loader'; -import NodeListItem from './NodeListItem'; - -export default class NodesPage extends React.Component { - state = { - nodes: [] - }; - - componentDidMount() { - this.fetchData(); - } - - fetchData = () => { - return ServiceFactory.nodesService().loadNodes(this).then(() => {}); - }; - - render() { - return ( - -
- {ServiceFactory.configurationService().get().displayName} Nodes -
- - - - - - - - - - - - - {this.state.nodes.map((node, index) => { - return ( - - ); - })} - -
NodeVersionCurrent heightBase targetUTxsMaintainer
- -
-
-
- ); - } -} diff --git a/src/peers/PeerList.js b/src/peers/PeerList.js deleted file mode 100644 index 7c75fc4..0000000 --- a/src/peers/PeerList.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import PeerListItem from './PeerListItem'; - -export default class PeerList extends React.Component { - static propTypes = { - peers: PropTypes.arrayOf(PropTypes.object).isRequired - }; - - render() { - return ( - - - - - - - - - - - {this.props.peers.map((peer, index) => { - peer.address = peer.address.replace("/",""); - if (peer.declaredAddress != "N/A") { peer.declaredAddress = peer.declaredAddress.replace("/",""); } - return (); - })} - -
AddressDeclared addressNode nameNode nonce
- ); - } -} diff --git a/src/peers/PeerListItem.js b/src/peers/PeerListItem.js deleted file mode 100644 index d5c6fc2..0000000 --- a/src/peers/PeerListItem.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export default class PeerListItem extends React.Component { - static propTypes = { - peer: PropTypes.object.isRequired - }; - - render() { - const {peer} = this.props; - return ( - - -
{peer.address}
- - -
{peer.declaredAddress}
- - -
{peer.name}
- - -
{peer.nonce}
- - - ); - } -} diff --git a/src/peers/PeersPage.js b/src/peers/PeersPage.js deleted file mode 100644 index 25bc196..0000000 --- a/src/peers/PeersPage.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; - -import ServiceFactory from '../services/ServiceFactory'; -import Loader from '../shared/Loader'; -import PeerList from './PeerList'; - -export default class PeersPage extends React.Component { - state = { - peers: [] - }; - - componentDidMount() { - this.fetchData(); - } - - fetchData = () => { - return ServiceFactory.peersService().loadPeers() - .then(peers => this.setState({peers})); - }; - - render() { - return ( - - -
- Peers - -
- -
-
- ); - } -} diff --git a/src/services/AddressService.js b/src/services/AddressService.js deleted file mode 100644 index 33100b2..0000000 --- a/src/services/AddressService.js +++ /dev/null @@ -1,71 +0,0 @@ -import groupBy from 'lodash/groupBy'; - -import Alias from '../shared/Alias'; -import Currency from '../shared/Currency'; -import Money from '../shared/Money'; -import {ApiClientService} from './ApiClientService'; - -export class AddressService extends ApiClientService { - constructor(transactionTransformerService, currencyService, configurationService) { - super(configurationService); - - this.transformer = transactionTransformerService; - this.currencyService = currencyService; - } - - loadBalance = (address) => { - return this.getApi().addresses.details(address).then(balanceResponse => { - const data = balanceResponse.data; - return { - regular: Money.fromCoins(data.regular, Currency.WAVES).toString(), - generating: Money.fromCoins(data.generating, Currency.WAVES).toString(), - available: Money.fromCoins(data.available, Currency.WAVES).toString(), - effective: Money.fromCoins(data.effective, Currency.WAVES).toString() - }; - }); - }; - - loadTransactions = (address, limit, after) => { - return this.getApi().transactions.address(address, limit, after).then(transactionsResponse => { - return this.transformer.transform(transactionsResponse.data[0]); - }); - }; - - loadAliases = (address) => { - return this.getApi().addresses.aliases(address).then(aliasesResponse => { - const lines = aliasesResponse.data.map(item => Alias.fromString(item).alias); - const grouped = groupBy(lines, item => item.toUpperCase().charAt(0)); - return Object.keys(grouped).sort().map(letter => ({ - letter, - aliases: grouped[letter].sort() - })); - }); - }; - - loadAssets = (address) => { - return this.getApi().addresses.assetsBalance(address).then(balanceResponse => { - const assets = balanceResponse.data.balances.map(item => { - const currency = Currency.fromIssueTransaction(item.issueTransaction); - this.currencyService.put(currency); - - const amount = Money.fromCoins(item.balance, currency); - - return { - id: item.assetId, - name: currency.toString(), - amount: amount.formatAmount() - }; - }); - - return assets; - }); - }; - - loadData = (address) => { - return this.getApi().addresses.data(address).then(dataResponse => dataResponse.data); - }; - - loadScript = (address) => { - return this.getApi().addresses.script(address).then(scriptResponse => scriptResponse.data); - } -} diff --git a/src/services/AliasService.js b/src/services/AliasService.js deleted file mode 100644 index b3ebbb3..0000000 --- a/src/services/AliasService.js +++ /dev/null @@ -1,12 +0,0 @@ -import {ApiClientService} from './ApiClientService'; - -export class AliasService extends ApiClientService { - constructor(configurationService) { - super(configurationService); - } - - loadAddress = (alias) => { - return this.getApi().aliases.address(alias) - .then(addressResponse => addressResponse.data.address); - }; -} diff --git a/src/services/ApiClientService.js b/src/services/ApiClientService.js deleted file mode 100644 index 2cf0313..0000000 --- a/src/services/ApiClientService.js +++ /dev/null @@ -1,9 +0,0 @@ -import {nodeApi} from '../shared/NodeApi'; - -export class ApiClientService { - constructor(configurationService) { - this.configurationService = configurationService; - } - - getApi = () => nodeApi(this.configurationService.get().apiBaseUrl); -} diff --git a/src/services/BlockService.js b/src/services/BlockService.js deleted file mode 100644 index f08a135..0000000 --- a/src/services/BlockService.js +++ /dev/null @@ -1,50 +0,0 @@ -import groupBy from 'lodash/groupBy'; - -import {ApiClientService} from './ApiClientService'; - -export class BlockService extends ApiClientService { - constructor(transactionTransformerService, infoService, configurationService) { - super(configurationService); - - this.transformer = transactionTransformerService; - this.infoService = infoService; - } - - loadSequence = (from, to) => { - return this.getApi().blocks.headers.sequence(from, to).then(blocksResponse => { - const blocks = blocksResponse.data.map(block => { - return { - height: block.height, - timestamp: block.timestamp, - baseTarget: block['nxt-consensus']['base-target'], - generator: block.generator, - signature: block.signature, - transactions: block.transactionCount - }; - }).reverse(); - - return blocks; - }); - }; - - loadBlock = (height) => { - let block; - - return Promise.all([this.infoService.loadHeight(), - this.getApi().blocks.at(height).then(blockResponse => { - block = blockResponse.data; - return this.transformer.transform(block.transactions); - } - )]).then(results => { - const maxHeight = results[0]; - const transactions = results[1]; - const groupedTransactions = transactions ? groupBy(transactions, 'type') : {}; - - return { - maxHeight, - block, - groupedTransactions - }; - }); - }; -} diff --git a/src/services/ConfigurationService.js b/src/services/ConfigurationService.js deleted file mode 100644 index a229b62..0000000 --- a/src/services/ConfigurationService.js +++ /dev/null @@ -1,71 +0,0 @@ -import configuredNetworks from '../configuration'; - -const CUSTOM_NETWORK_ID = 'custom'; -const CUSTOM_NETWORK_NAME = 'Custom'; -const copyAndFreeze = object => Object.freeze(Object.assign({}, object)); - -const trimEnd = (string, char) => { - while (string.charAt(string.length - 1) === char) { - string = string.substring(0, string.length - 1); - } - - return string; -}; - -export class ConfigurationService { - constructor(storageService) { - this.storageService = storageService; - - this.networks = configuredNetworks.slice(); - this.customNetwork = null; - const saved = this.storageService.loadConfiguration(); - if (saved) { - this.selectedIndex = saved.selectedIndex; - if (saved.customNetwork) { - this.networks.push(saved.customNetwork); - this.customNetwork = saved.customNetwork; - } - } else { - this.selectedIndex = 0; - } - } - - get = () => copyAndFreeze(this.networks[this.selectedIndex]); - - all = () => this.networks.slice(); - - custom = () => this.customNetwork ? copyAndFreeze(this.customNetwork) : null; - - select = (networkId) => { - const index = this.networks.findIndex(item => item.networkId === networkId); - if (index < 0) { - throw new Error(`Network with id ${networkId} is not found`); - } - - this.selectedIndex = index; - this.save(); - }; - - update = ({apiBaseUrl}) => { - if (!this.customNetwork) { - this.customNetwork = { - networkId: CUSTOM_NETWORK_ID, - displayName: CUSTOM_NETWORK_NAME, - }; - this.networks.push(this.customNetwork); - } - - this.customNetwork.apiBaseUrl = trimEnd(apiBaseUrl, '/'); - this.customNetwork.nodes = [{url: apiBaseUrl}]; - this.selectedIndex = this.networks.length - 1; - - this.save(); - }; - - save = () => { - this.storageService.saveConfiguration({ - selectedIndex: this.selectedIndex, - customNetwork: this.customNetwork - }); - } -} diff --git a/src/services/CurrencyService.js b/src/services/CurrencyService.js deleted file mode 100644 index 5874e84..0000000 --- a/src/services/CurrencyService.js +++ /dev/null @@ -1,60 +0,0 @@ -import Currency from '../shared/Currency'; -import {ApiClientService} from './ApiClientService'; - -const FAILURE = new Currency({ - id: 'failure', - displayName: 'Failed to load', - precision: 8 -}); - -export class CurrencyService extends ApiClientService { - constructor(configurationService) { - super(configurationService); - this.currencyCache = {}; - this.promisesCashe = {}; - } - - put = currency => { - if (this.currencyCache[currency.id]) { - return this.currencyCache[currency.id]; - } else { - this.currencyCache[currency.id] = currency; - return currency; - } - }; - - get = assetId => { - if (!assetId) { - return Promise.resolve(Currency.WAVES); - } - - const currency = this.currencyCache[assetId]; - if (currency) { - return Promise.resolve(currency); - } else { - if (this.promisesCashe[assetId]) { - return this.promisesCashe[assetId]; - } - - const promise = this.getApi().transactions.info(assetId) - .then(infoResponse => { - const c = Currency.fromIssueTransaction(infoResponse.data); - return this.put(c); - }) - .catch(error => { - console.log(error); - - if (error.response) { - console.log(error.response.data); - console.log(error.response.status); - } - - return FAILURE; - }); - - this.promisesCashe[assetId] = promise; - - return promise; - } - }; -} diff --git a/src/services/InfoService.js b/src/services/InfoService.js deleted file mode 100644 index d7be837..0000000 --- a/src/services/InfoService.js +++ /dev/null @@ -1,43 +0,0 @@ -import axios from 'axios'; - -import {nodeApi} from '../shared/NodeApi'; -import {ApiClientService} from './ApiClientService'; - -export class InfoService extends ApiClientService { - constructor(configurationService) { - super(configurationService); - } - - loadHeight = () => { - return this.getApi().blocks.height() - .then(heightResponse => heightResponse.data.height); - }; - - loadInfo = () => { - const api = this.getApi(); - - return axios.all([ - api.version(), - this.loadHeight(), - api.baseTarget() - ]).then(axios.spread((version, height, baseTarget) => { - return { - 'Version': version.data.version, - 'Current height': height, - 'Base Target': baseTarget.data.baseTarget - }; - })); - }; - - loadDelay = (info) => { - const api = this.getApi(); - - return api.blocks.headers.last().then(headerResponse => { - return api.blocks.delay(headerResponse.data.signature, headerResponse.data.height - 2) - }).then(delayResponse => { - const delay = (parseInt(delayResponse.data.delay) / 1000 / 60.0).toFixed(1); - - return Object.assign({}, info, {'Avg Block delay': `${delay} minutes`}) ; - }); - }; -} diff --git a/src/services/MoneyService.js b/src/services/MoneyService.js deleted file mode 100644 index d375422..0000000 --- a/src/services/MoneyService.js +++ /dev/null @@ -1,19 +0,0 @@ -import Money from '../shared/Money'; - -export class MoneyService { - constructor(currencyService) { - this.currencyService = currencyService; - } - - fromTokens = (assetId, amount) => { - return this.currencyService.get(assetId).then(currency => { - return Money.fromTokens(amount, currency); - }); - }; - - fromCoins = (assetId, amount) => { - return this.currencyService.get(assetId).then(currency => { - return Money.fromCoins(amount, currency); - }); - }; -} diff --git a/src/services/NodesService.js b/src/services/NodesService.js deleted file mode 100644 index b6f5fe7..0000000 --- a/src/services/NodesService.js +++ /dev/null @@ -1,51 +0,0 @@ -import axios from 'axios'; - -import {nodeApi} from '../shared/NodeApi'; -import {ApiClientService} from './ApiClientService'; - -export class NodesService extends ApiClientService { - constructor(configurationService) { - super(configurationService); - } - - loadNodes = (_this) => { - let chain = Promise.resolve(); - - const nodes = this.configurationService.get().nodes.slice(); - - nodes.map((node, index) => { - const api = nodeApi(node.url); - chain = chain - .then(() => { - return new Promise((resolve, reject) => { - axios.all([ - api.version(), - api.blocks.height(), - api.baseTarget(), - api.transactions.utxSize() - ]).then(axios.spread((version, height, baseTarget, unconfirmedTxCount) => { - const newNode = { - ...node, - version: version.data.version, - height: height.data.height, - baseTarget: baseTarget.data.baseTarget, - unconfirmedTxCount: unconfirmedTxCount.data.size - }; - - resolve({ - index, - node: newNode - }); - })) - }) - }) - .then((resolve) => { - let nodes = _this.state.nodes; - nodes[resolve.index] = resolve.node; - _this.setState({nodes}); - }); - }); - - return chain; - } -} diff --git a/src/services/PeersService.js b/src/services/PeersService.js deleted file mode 100644 index 70f4d63..0000000 --- a/src/services/PeersService.js +++ /dev/null @@ -1,18 +0,0 @@ -import {ApiClientService} from './ApiClientService'; - -export class PeersService extends ApiClientService { - constructor(configurationService) { - super(configurationService); - } - - loadPeers = () => { - return this.getApi().peers().then(response => { - return response.data.peers.map(item => ({ - address: item.address, - declaredAddress: item.declaredAddress, - name: item.peerName, - nonce: item.peerNonce - })); - }); - }; -} diff --git a/src/services/SearchService.js b/src/services/SearchService.js deleted file mode 100644 index 40b3c18..0000000 --- a/src/services/SearchService.js +++ /dev/null @@ -1,28 +0,0 @@ -import {routes} from '../shared/Routing'; -import {ApiClientService} from './ApiClientService'; - -export class SearchService extends ApiClientService { - constructor(configurationService) { - super(configurationService); - } - search = query => { - if (!query) - return Promise.resolve(); - - query = query.trim(); - - const api = this.getApi(); - return api.addresses.validate(query).then(validateResponse => { - if (validateResponse.data.valid) - return routes.addresses.one(query); - - return api.blocks.heightBySignature(query).then(heightResponse => { - return routes.blocks.one(heightResponse.data.height); - }); - }).catch(() => { - return api.transactions.info(query).then(infoResponse => { - return routes.transactions.one(infoResponse.data.id); - }) - }); - }; -} diff --git a/src/services/ServiceFactory.js b/src/services/ServiceFactory.js deleted file mode 100644 index 0b6b47f..0000000 --- a/src/services/ServiceFactory.js +++ /dev/null @@ -1,58 +0,0 @@ -import {MoneyService} from './MoneyService'; -import {CurrencyService} from './CurrencyService'; -import {TransactionTransformerService} from './TransactionTransformerService'; -import {SearchService} from './SearchService'; -import {StorageService} from './StorageService'; -import {SpamDetectionService} from './SpamDetectionService'; -import {PeersService} from './PeersService'; -import {NodesService} from './NodesService'; -import {TransactionService} from './TransactionService'; -import {BlockService} from './BlockService'; -import {AddressService} from './AddressService'; -import {InfoService} from './InfoService'; -import {AliasService} from './AliasService'; -import {ConfigurationService} from './ConfigurationService'; - -class ServiceFactory { - constructor() { - this._storageService = new StorageService(); - this._configurationService = new ConfigurationService(this._storageService); - this._currencyService = new CurrencyService(this._configurationService); - this._spamDetectionService = new SpamDetectionService(this._storageService, this._configurationService); - this._transactionTransformerService = new TransactionTransformerService(this._currencyService, - this._spamDetectionService); - this._infoService = new InfoService(this._configurationService); - } - - currencyService = () => this._currencyService; - - moneyService = () => new MoneyService(this._currencyService); - - transactionTransformerService = () => this._transactionTransformerService; - - searchService = () => new SearchService(this._configurationService); - - peersService = () => new PeersService(this._configurationService); - - nodesService = () => new NodesService(this._configurationService); - - transactionService = () => new TransactionService(this._transactionTransformerService, this._configurationService); - - blockService = () => new BlockService(this._transactionTransformerService, - this._infoService, - this._configurationService); - - addressService = () => new AddressService(this._transactionTransformerService, - this._currencyService, - this._configurationService); - - infoService = () => this._infoService; - - aliasService = () => new AliasService(this._configurationService); - - configurationService = () => this._configurationService; -} - -const factoryInstance = new ServiceFactory(); - -export default factoryInstance; diff --git a/src/services/SpamDetectionService.js b/src/services/SpamDetectionService.js deleted file mode 100644 index 0955ab6..0000000 --- a/src/services/SpamDetectionService.js +++ /dev/null @@ -1,67 +0,0 @@ -import {thirdPartyApi} from '../shared/ThirdPartyApi'; - -const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000; - -export class SpamDetectionService { - constructor(storageService, configurationService) { - this.storageService = storageService; - this.configurationService = configurationService; - this.updating = false; - this.active = !!this.spamListUrl(); - - if (this.active) { - this.cache = storageService.loadAntispamCache() || { - spamAssets: {} - }; - } - } - - isSpam = (assetId) => { - if (!this.active) { - return false; - } - - const result = !!this.cache.spamAssets[assetId]; - - this.updateCacheIfNeeded(); - - return result; - }; - - updateCacheIfNeeded = () => { - if (this.updating) - return; - - if (!this.cache.expirationTime || this.cache.expirationTime <= new Date().getTime()) { - this.updating = true; - - const api = thirdPartyApi(this.spamListUrl()); - api.antispamList().then(listResponse => { - this.cache.spamAssets = this.parseAssetList(listResponse.data); - // cache should expire in one day - this.cache.expirationTime = new Date().getTime() + MILLISECONDS_PER_DAY; - this.storageService.saveAntispamCache(this.cache); - }).finally(() => { - this.updating = false; - }); - } - }; - - parseAssetList = (listAsString) => { - const lines = listAsString.split('\n'); - const result = {}; - lines.forEach(line => { - const parts = line.split(','); - if (parts.length > 0) { - const assetId = parts[0].trim(); - if (assetId) { - result[assetId] = true; - } - } - }); - - return result; - }; - - spamListUrl = () => this.configurationService.get().spamListUrl; -} diff --git a/src/services/StorageService.js b/src/services/StorageService.js deleted file mode 100644 index a475e23..0000000 --- a/src/services/StorageService.js +++ /dev/null @@ -1,37 +0,0 @@ -const ANTISPAM_CACHE_KEY = 'AntispamCache'; -const CONFIGURATION = 'Configuration'; - -export class StorageService { - constructor() { - this.storage = window.localStorage; - } - - loadObject = key => { - const objectAsString = this.storage.getItem(key); - - if (!objectAsString) - return null; - - return JSON.parse(objectAsString); - }; - - saveObject = (key, object) => { - this.storage.setItem(key, JSON.stringify(object)); - }; - - loadAntispamCache = () => { - return this.loadObject(ANTISPAM_CACHE_KEY); - }; - - saveAntispamCache = (cache) => { - this.saveObject(ANTISPAM_CACHE_KEY, cache); - }; - - loadConfiguration = () => { - return this.loadObject(CONFIGURATION); - }; - - saveConfiguration = (configuration) => { - this.saveObject(CONFIGURATION, configuration); - }; -} diff --git a/src/services/TransactionService.js b/src/services/TransactionService.js deleted file mode 100644 index 96079ee..0000000 --- a/src/services/TransactionService.js +++ /dev/null @@ -1,22 +0,0 @@ -import {api} from '../shared/NodeApi'; -import {ApiClientService} from './ApiClientService'; - -export class TransactionService extends ApiClientService { - constructor(transactionTransformerService, configurationService) { - super(configurationService); - - this.transformer = transactionTransformerService; - } - - loadTransaction = (id) => { - return this.getApi().transactions.info(id).then(infoResponse => { - return this.transformer.transform(infoResponse.data); - }); - }; - - loadUnconfirmed = () => { - return this.getApi().transactions.unconfirmed().then(response => { - return this.transformer.transform(response.data); - }) - }; -} diff --git a/src/services/TransactionTransformerService.js b/src/services/TransactionTransformerService.js deleted file mode 100644 index a15b938..0000000 --- a/src/services/TransactionTransformerService.js +++ /dev/null @@ -1,266 +0,0 @@ -import Currency from '../shared/Currency'; -import Money from '../shared/Money'; -import OrderPrice from '../shared/OrderPrice'; -import DateTime from '../shared/DateTime'; - -const transformMultiple = (currencyService, spamDetectionService, transactions) => { - const promises = transactions.map(item => transformSingle(currencyService, spamDetectionService, item)); - - return Promise.all(promises); -}; - -const transformSingle = (currencyService, spamDetectionService, tx) => { - switch (tx.type) { - case 2: - case 4: - return transformTransfer(currencyService, spamDetectionService, tx); - - case 3: - return transformIssue(currencyService, tx); - - case 5: - return transformReissue(currencyService, tx); - - case 6: - return tranformBurn(currencyService, tx); - - case 7: - return transformExchange(currencyService, tx); - - case 8: - return transformLease(currencyService, tx); - - case 9: - return transformLeaseCancel(currencyService, tx); - - case 10: - return transformAlias(currencyService, tx); - - case 11: - return transformMassTransfer(currencyService, spamDetectionService, tx); - - case 12: - return transformData(currencyService, tx); - - case 13: - return transformScript(currencyService, tx); - - case 14: - return transformSponsorship(currencyService, tx); - - default: - return Promise.resolve(Object.assign({}, tx)); - } -}; - -const copyMandatoryAttributes = tx => ({ - id: tx.id, - type: tx.type, - timestamp: new DateTime(tx.timestamp), - sender: tx.sender, - height: tx.height -}); - -const loadAmountAndFeeCurrencies = (currencyService, amountAssetId, feeAssetId) => { - return Promise.all([ - currencyService.get(amountAssetId), - currencyService.get(feeAssetId) - ]); -}; - -const transformData = (currencyService, tx) => { - return currencyService.get(tx.feeAssetId).then(feeCurrency => { - return Object.assign(copyMandatoryAttributes(tx), { - data: tx.data, - fee: Money.fromCoins(tx.fee, feeCurrency) - }) - }); -}; - -const transformScript = (currencyService, tx) => { - return currencyService.get(tx.feeAssetId).then(feeCurrency => { - return Object.assign(copyMandatoryAttributes(tx), { - script: tx.script, - fee: Money.fromCoins(tx.fee, feeCurrency) - }) - }); -}; - -const transformSponsorship = (currencyService, tx) => { - return loadAmountAndFeeCurrencies(currencyService, tx.assetId, tx.feeAssetId).then(pair => { - const sponsoredCurrency = pair[0]; - const feeCurrency = pair[1]; - - const sponsoredFee = tx.minSponsoredAssetFee ? - Money.fromCoins(tx.minSponsoredAssetFee, sponsoredCurrency) : - null; - - return Object.assign(copyMandatoryAttributes(tx), { - fee: Money.fromCoins(tx.fee, feeCurrency), - sponsoredFee - }); - }); -}; - -const transformMassTransfer = (currencyService, spamDetectionService, tx) => { - return loadAmountAndFeeCurrencies(currencyService, tx.assetId, tx.feeAssetId).then(pair => { - const amountCurrency = pair[0]; - const feeCurrency = pair[1]; - - const transfers = tx.transfers.map(item => ({ - recipient: item.recipient, - amount: Money.fromCoins(item.amount, amountCurrency) - })); - - return Object.assign(copyMandatoryAttributes(tx), { - fee: Money.fromCoins(tx.fee, feeCurrency), - attachment: tx.attachment, - totalAmount: Money.fromCoins(tx.totalAmount, amountCurrency), - transferCount: tx.transferCount, - isSpam: spamDetectionService.isSpam(tx.assetId), - transfers - }); - }); -}; - -const transformAlias = (currencyService, tx) => { - return Promise.resolve( - Object.assign(copyMandatoryAttributes(tx), { - fee: Money.fromCoins(tx.fee, Currency.WAVES), - alias: tx.alias - }) - ); -}; - -const transformLease = (currencyService, tx) => { - return currencyService.get(tx.feeAssetId).then(feeCurrency => { - return Object.assign(copyMandatoryAttributes(tx), { - recipient: tx.recipient, - fee: Money.fromCoins(tx.fee, feeCurrency), - amount: Money.fromCoins(tx.amount, Currency.WAVES), - status: tx.status - }) - }); -}; - -const transformLeaseCancel = (currencyService, tx) => { - return currencyService.get(tx.feeAssetId).then(feeCurrency => { - return Object.assign(copyMandatoryAttributes(tx), { - fee: Money.fromCoins(tx.fee, feeCurrency), - leaseId: tx.leaseId, - recipient: tx.lease ? tx.lease.recipient : null - }); - }); -}; - -const transformExchange = (currencyService, tx) => { - const buyOrder = tx.order1.orderType === 'buy' ? tx.order1 : tx.order2; - const sellOrder = tx.order2.orderType === 'sell' ? tx.order2 : tx.order1; - const assetPair = buyOrder.assetPair; - - return Promise.all([ - currencyService.get(assetPair.amountAsset), - currencyService.get(assetPair.priceAsset) - ]).then(pair => { - const currencyPair = { - amountAsset: pair[0], - priceAsset: pair[1] - }; - - const price = OrderPrice.fromBackendPrice(tx.price, currencyPair); - const amount = Money.fromCoins(tx.amount, currencyPair.amountAsset); - - return Object.assign(copyMandatoryAttributes(tx), { - fee: Money.fromCoins(tx.fee, Currency.WAVES), - buyFee: Money.fromCoins(tx.buyMatcherFee, Currency.WAVES), - sellFee: Money.fromCoins(tx.sellMatcherFee, Currency.WAVES), - price, - amount, - total: Money.fromTokens(price.toTokens() * amount.toTokens(), currencyPair.priceAsset), - buyOrder: transformOrder(buyOrder, currencyPair), - sellOrder: transformOrder(sellOrder, currencyPair), - sender: sellOrder.sender, - recipient: buyOrder.sender - }); - }); -}; - -const transformOrder = (order, assetPair) => { - return { - id: order.id, - sender: order.sender, - assetPair, - orderType: order.orderType, - amount: Money.fromCoins(order.amount, assetPair.amountAsset), - price: OrderPrice.fromBackendPrice(order.price, assetPair), - timestamp: new DateTime(order.timestamp), - expiration: new DateTime(order.expiration), - fee: Money.fromCoins(order.matcherFee, Currency.WAVES) - }; -}; - -const tranformBurn = (currencyService, tx) => { - return currencyService.get(tx.assetId).then(currency => { - return Object.assign(copyMandatoryAttributes(tx), { - amount: Money.fromCoins(tx.amount, currency), - fee: Money.fromCoins(tx.fee, Currency.WAVES) - }); - }); -}; - -const transformReissue = (currencyService, tx) => { - return currencyService.get(tx.assetId).then(currency => { - return Object.assign(copyMandatoryAttributes(tx), { - amount: Money.fromCoins(tx.quantity, currency), - fee: Money.fromCoins(tx.fee, Currency.WAVES), - reissuable: tx.reissuable, - - }); - }); -}; - -const transformIssue = (currencyService, tx) => { - const c = Currency.fromIssueTransaction(tx); - currencyService.put(c); - - return currencyService.get(c.id).then(currency => { - return Object.assign(copyMandatoryAttributes(tx), { - amount: Money.fromCoins(tx.quantity, currency), - fee: Money.fromCoins(tx.fee, Currency.WAVES), - name: tx.name, - reissuable: tx.reissuable, - decimals: tx.decimals, - description: tx.description - }); - }); -}; - -const transformTransfer = (currencyService, spamDetectionService, tx) => { - return loadAmountAndFeeCurrencies(currencyService, tx.assetId, tx.feeAssetId).then(pair => { - const amountCurrency = pair[0]; - const feeCurrency = pair[1]; - - return Object.assign(copyMandatoryAttributes(tx), { - amount: Money.fromCoins(tx.amount, amountCurrency), - fee: Money.fromCoins(tx.fee, feeCurrency), - attachment: tx.attachment, - recipient: tx.recipient, - isSpam: spamDetectionService.isSpam(tx.assetId) - }); - }); -}; - - -export class TransactionTransformerService { - constructor(currencyService, spamDetectionService) { - this.currencyService = currencyService; - this.spamDetectionService = spamDetectionService; - } - - transform = (input) => { - if (Array.isArray(input)) - return transformMultiple(this.currencyService, this.spamDetectionService, input); - - return transformSingle(this.currencyService, this.spamDetectionService, input); - }; -} diff --git a/src/shared/Alias.js b/src/shared/Alias.js deleted file mode 100644 index 4c9704d..0000000 --- a/src/shared/Alias.js +++ /dev/null @@ -1,27 +0,0 @@ -const ALIAS_PREFIX = 'alias'; - -export default class Alias { - constructor(networkCode, alias) { - this.networkCode = networkCode; - this.alias = alias; - } - - static isAlias = candidate => { - return candidate.trim().search(ALIAS_PREFIX) == 0; - }; - - static fromString = candidate => { - var parts = candidate.split(':'); - if (parts.length != 3) - throw new Error('Too few elements in alias: ' + candidate); - - if (parts[0] !== ALIAS_PREFIX) - throw new Error('Unexpected alias prefix: ' + candidate); - - return new Alias(parts[1], parts[2]) - }; - - toString() { - return ALIAS_PREFIX + ':' + this.networkCode + ':' + this.alias; - } -} diff --git a/src/shared/BlockRef.js b/src/shared/BlockRef.js deleted file mode 100644 index 97a6f96..0000000 --- a/src/shared/BlockRef.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Link} from 'react-router-dom'; - -import {routes} from './Routing'; - -class BlockRef extends React.PureComponent { - static propTypes = { - height: PropTypes.number.isRequired - }; - - render() { - const {height} = this.props; - - return ({height}); - } -} - -export default BlockRef; diff --git a/src/shared/CopyButton.js b/src/shared/CopyButton.js deleted file mode 100644 index 5c29488..0000000 --- a/src/shared/CopyButton.js +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import CopyToClipboard from 'react-copy-to-clipboard'; - -const MESSAGE_DELAY_MILLISECONDS = 1000; - -const Copy = ({text, onCopy}) => { - return -
Copy
-
-}; - -Copy.propTypes = { - text: PropTypes.string, - onCopy: PropTypes.func -}; - -Copy.defaultProps = { - text: '', - onCopy: undefined -}; - -const Copied = () =>
Copied!
; - -class CopyButton extends React.PureComponent { - static propTypes = Copy.propTypes; - static defaultProps = Copy.defaultProps; - - state = { - hasCopied: false - }; - - handleCopy = (text, result) => { - if (this.props.onCopy) { - this.props.onCopy(text, result); - } - - this.setState({hasCopied: true}); - setTimeout(() => this.setState({hasCopied: false}), MESSAGE_DELAY_MILLISECONDS); - }; - - render() { - return this.state.hasCopied ? : ; - } -} - -export default CopyButton; diff --git a/src/shared/Currency.js b/src/shared/Currency.js deleted file mode 100644 index 6e4c13f..0000000 --- a/src/shared/Currency.js +++ /dev/null @@ -1,40 +0,0 @@ -import {Decimal} from 'decimal.js'; - -export default class Currency { - constructor(data) { - data = data || {}; - - this.id = data.id; // base58 encoded asset id of the currency - this.displayName = data.displayName; - this.shortName = data.shortName || data.displayName; - this.precision = data.precision; // number of decimal places after a decimal point - - if (data.roundingMode !== undefined) { - this.roundingMode = data.roundingMode; - } else { - this.roundingMode = Decimal.ROUND_HALF_UP; - } - } - - static WAVES = new Currency({ - id: '', - displayName: 'Acryl', - shortName: 'ACRYL', - precision: 8 - }); - - static fromIssueTransaction = issueTransaction => { - return new Currency({ - id: issueTransaction.assetId, - displayName: issueTransaction.name, - precision: issueTransaction.decimals - }); - }; - - toString() { - if (this.shortName) - return this.shortName; - - return this.displayName; - } -} diff --git a/src/shared/CurrencyRef.js b/src/shared/CurrencyRef.js deleted file mode 100644 index 8b108f7..0000000 --- a/src/shared/CurrencyRef.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import Currency from './Currency'; -import TransactionRef from './TransactionRef'; - -const CurrencyRef = ({currency}) => { - if (currency === Currency.WAVES) - return currency.toString(); - - return ; -}; - -CurrencyRef.propTypes = { - currency: PropTypes.shape({ - id: PropTypes.string - }).isRequired -}; - -export default CurrencyRef; diff --git a/src/shared/DataInfo.js b/src/shared/DataInfo.js deleted file mode 100644 index 916b9da..0000000 --- a/src/shared/DataInfo.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import EmptyData from './EmptyData'; - -export default class DataInfo extends React.PureComponent { - static propTypes = { - data: PropTypes.arrayOf(PropTypes.shape({ - key: PropTypes.string, - type: PropTypes.string, - value: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number - ]) - })).isRequired - }; - - render() { - const isEmpty = this.props.data.length == 0; - const rowClassName = 'data-container' + (isEmpty ? ' empty' : ''); - - return ( -
- {isEmpty ? :
{JSON.stringify(this.props.data, null, 2)}
} -
- ); - } -} diff --git a/src/shared/DateTime.js b/src/shared/DateTime.js deleted file mode 100644 index 158025c..0000000 --- a/src/shared/DateTime.js +++ /dev/null @@ -1,17 +0,0 @@ -const DEFAULT_LOCALE = 'ru-Ru'; - -export default class DateTime { - instant; - date; - time; - - constructor(timestamp) { - this.instant = new Date(timestamp); - this.date = this.instant.toLocaleDateString(DEFAULT_LOCALE); - this.time = this.instant.toLocaleTimeString(DEFAULT_LOCALE); - } - - toLongString() { - return this.time + ', ' + this.date; - } -} diff --git a/src/shared/Dictionary.js b/src/shared/Dictionary.js deleted file mode 100644 index 3a072df..0000000 --- a/src/shared/Dictionary.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import DictionaryItem from './DictionaryItem'; - -export default class Dictionary extends React.Component { - static propTypes = { - items: PropTypes.arrayOf(PropTypes.shape(DictionaryItem.propTypes)).isRequired - }; - - render() { - return ( -
- {this.props.items.map((item, index) => { - return - })} -
- ); - } -} diff --git a/src/shared/DictionaryItem.js b/src/shared/DictionaryItem.js deleted file mode 100644 index a8ea17d..0000000 --- a/src/shared/DictionaryItem.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export default class DictionaryItem extends React.PureComponent { - static propTypes = { - label: PropTypes.string.isRequired, - value: PropTypes.node, - action: PropTypes.node - }; - - render() { - return ( -
-
{this.props.label}
-
{ - this.props.action ?
{this.props.value}
: this.props.value - }
- {this.props.action &&
- {this.props.action} -
} -
- ); - } -} - -{/*
*/} - {/*
{this.props.label}
*/} - {/*
{this.props.action &&
{this.props.value}
}
*/} - {/*{this.props.action &&
*/} - {/*{this.props.action}*/} - {/*
}*/} -{/*
*/} diff --git a/src/shared/EmptyData.js b/src/shared/EmptyData.js deleted file mode 100644 index 3e4ce7f..0000000 --- a/src/shared/EmptyData.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; - -const EmptyData = (props) => ( -
-
-
No data
-
-); - -export default EmptyData; diff --git a/src/shared/EndpointRef.js b/src/shared/EndpointRef.js deleted file mode 100644 index 6cfb6b4..0000000 --- a/src/shared/EndpointRef.js +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Link} from 'react-router-dom'; - -import Alias from './Alias'; -import {routes} from './Routing'; - -const REGULAR = 'regular'; -const BRIGHT = 'bright'; - -const appearanceToClassName = appearance => { - switch (appearance) { - case REGULAR: - return 'no-accent'; - - default: - return ''; - } -}; - -class AddressRef extends React.PureComponent { - static propTypes = { - address: PropTypes.string.isRequired, - title: PropTypes.string, - className: PropTypes.string - }; - - render() { - const {address, className} = this.props; - const title = this.props.title || address; - - return ({title}); - } -} - -class AliasRef extends React.PureComponent { - static propTypes = { - alias: PropTypes.string.isRequired, - title: PropTypes.string, - className: PropTypes.string - }; - - render() { - const {alias, className} = this.props; - const a = Alias.fromString(alias); - const title = this.props.title || a.alias; - - return ({title.substring(0, 50)}); - } -} - -const EndpointRef = ({endpoint, title, appearance}) => { - const className = appearanceToClassName(appearance); - - if (Alias.isAlias(endpoint)) { - return ; - } - - return ; -}; - -EndpointRef.propTypes = { - endpoint: PropTypes.string.isRequired, - title: PropTypes.string, - appearance: PropTypes.oneOf([REGULAR, BRIGHT]) -}; - -EndpointRef.defaultProps = { - appearance: BRIGHT -}; - -export default EndpointRef; diff --git a/src/shared/Error.js b/src/shared/Error.js deleted file mode 100644 index 6b7c1a7..0000000 --- a/src/shared/Error.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export default class Error extends React.PureComponent { - static propTypes = { - title: PropTypes.string - }; - - static defaultProps = { - title: 'Unexpected failure' - }; - - render() { - const {title} = this.props; - - return ( -
-
-
-
- ); - } -} diff --git a/src/shared/GoBack.js b/src/shared/GoBack.js deleted file mode 100644 index cc97d50..0000000 --- a/src/shared/GoBack.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import {withRouter} from 'react-router'; - -class GoBack extends React.PureComponent { - state = { - enabled: true - }; - - componentDidMount() { - if (this.props.history.length === 1) - this.setState({enabled: false}); - } - - handleClick = () => { - if (this.state.enabled) { - this.props.history.goBack(); - } - }; - - render() { - const linkClassName = this.state.enabled ? 'no-accent' : 'fade'; - - return ( -
- - Back -
- ); - } -} - -export default withRouter(GoBack); diff --git a/src/shared/Headline.js b/src/shared/Headline.js deleted file mode 100644 index 89e490b..0000000 --- a/src/shared/Headline.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import CopyButton from './CopyButton'; - -const Headline = (props) => { - return ( -
- {props.title} - / {props.subtitle} - {props.copyVisible && } -
- ); -}; - -Headline.propTypes = { - title: PropTypes.string.isRequired, - subtitle: PropTypes.string.isRequired, - copyVisible: PropTypes.bool -}; - -Headline.defaultProps = { - copyVisible: true -}; - -export default Headline; diff --git a/src/shared/Loader.js b/src/shared/Loader.js deleted file mode 100644 index 30ec5b5..0000000 --- a/src/shared/Loader.js +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import Loading from './Loading'; -import Error from './Error'; - -export default class Loader extends React.Component { - static propTypes = { - errorTitle: PropTypes.string, - loadingTitle: PropTypes.string, - fetchData: PropTypes.func.isRequired - }; - - state = { - loading: false, - hasError: false - }; - - componentDidMount() { - this.setState({loading: true}); - this.props.fetchData() - .then(value => { - this.setState({loading: false}); - - return value; - }) - .catch(error => { - console.log(error); - - this.setState({ - loading: false, - hasError: true - }); - }); - } - - render() { - if (this.state.loading) { - return ; - } - - if (this.state.hasError) { - return ; - } - - return this.props.children; - } -} diff --git a/src/shared/Loading.js b/src/shared/Loading.js deleted file mode 100644 index c9d2a52..0000000 --- a/src/shared/Loading.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -export default class Loading extends React.PureComponent { - render() { - return ( -
-
-
- ); - } -} diff --git a/src/shared/Money.js b/src/shared/Money.js deleted file mode 100644 index d977df3..0000000 --- a/src/shared/Money.js +++ /dev/null @@ -1,123 +0,0 @@ -import {Decimal} from 'decimal.js'; -import isNumber from 'lodash/isNumber'; -import Currency from './Currency'; - -const DECIMAL_SEPARATOR = '.'; -const THOUSANDS_SEPARATOR = ','; - -const format = (value, currency) => value.toFixed(currency.precision, currency.roundingMode); -const validateCurrency = (expected, actual) => { - if (expected.id !== actual.id) - throw new Error('Currencies must be the same for operands. Expected: ' + - expected.displayName + '; Actual: ' + actual.displayName); -}; - -const fromTokensToCoins = (valueInTokens, currencyPrecision) => valueInTokens - .mul(Math.pow(10, currencyPrecision)).trunc(); - -const fromCoinsToTokens = (valueInCoins, currencyPrecision) => valueInCoins - .trunc().div(Math.pow(10, currencyPrecision)); - -// in 2016 Safari doesn't support toLocaleString() -// that's why we need this method -const formatWithThousandsSeparator = (formattedAmount) => { - var parts = formattedAmount.split(DECIMAL_SEPARATOR); - parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, THOUSANDS_SEPARATOR); - - return parts.join(DECIMAL_SEPARATOR); -}; - -export default class Money { - constructor(amount, currency) { - if (amount === undefined) - throw new Error('Amount is required'); - - if (currency === undefined) - throw new Error('Currency is required'); - - this.amount = new Decimal(amount) - .toDecimalPlaces(currency.precision, Decimal.ROUND_FLOOR); - this.currency = currency; - } - - static fromTokens = (amount, currency) => new Money(amount, currency); - static fromCoins = (amount, currency) => { - currency = currency || {}; - if (currency.precision === undefined) - throw new Error('A valid currency must be provided'); - - amount = new Decimal(amount); - amount = amount.div(Math.pow(10, currency.precision)); - - return new Money(amount, currency); - }; - - formatAmount = (stripZeroes, useThousandsSeparator) => { - const result = stripZeroes ? - this.toTokens().toFixed(this.amount.decimalPlaces()) : - format(this.amount, this.currency); - - return useThousandsSeparator ? formatWithThousandsSeparator(result) : result; - }; - - toTokens = () => { - var result = fromCoinsToTokens(fromTokensToCoins(this.amount, this.currency.precision), - this.currency.precision); - - return result.toNumber(); - }; - - toCoins = () => fromTokensToCoins(this.amount, this.currency.precision).toNumber(); - - plus = money => { - validateCurrency(this.currency, money.currency); - - return new Money(this.amount.plus(money.amount), this.currency); - }; - - minus = money => { - validateCurrency(this.currency, money.currency); - - return new Money(this.amount.minus(money.amount), this.currency); - }; - - greaterThan = other => { - validateCurrency(this.currency, other.currency); - - return this.amount.greaterThan(other.amount); - }; - - greaterThanOrEqualTo = other => { - validateCurrency(this.currency, other.currency); - - return this.amount.greaterThanOrEqualTo(other.amount); - }; - - lessThan = other => { - validateCurrency(this.currency, other.currency); - - return this.amount.lessThan(other.amount); - }; - - lessThanOrEqualTo = other => { - validateCurrency(this.currency, other.currency); - - return this.amount.lessThanOrEqualTo(other.amount); - }; - - multiply = multiplier => { - if (!isNumber(multiplier)) - throw new Error('Number is expected'); - - if (isNaN(multiplier)) - throw new Error('Multiplication by NaN is not supported'); - - return new Money(this.amount.mul(multiplier), this.currency); - }; - - toString = () => this.formatAmount(true, true) + ' ' + this.currency.toString(); -} - -// set up decimal to format 0.00000001 as is instead of 1e-8 -Decimal.config({toExpNeg: -(Currency.WAVES.precision + 1)}); - diff --git a/src/shared/NoData.js b/src/shared/NoData.js deleted file mode 100644 index ad96534..0000000 --- a/src/shared/NoData.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export default class NoData extends React.PureComponent { - static propTypes = { - title: PropTypes.string - }; - - static defaultProps = { - title: 'No data' - }; - - render() { - const {title} = this.props; - - return ( -
-
-
-
- ); - } -} diff --git a/src/shared/NodeApi.js b/src/shared/NodeApi.js deleted file mode 100644 index 6b30617..0000000 --- a/src/shared/NodeApi.js +++ /dev/null @@ -1,84 +0,0 @@ -import axios from 'axios'; -import * as rax from 'retry-axios'; - -import DateTime from './DateTime'; - -const TRANSACTIONS_BY_ADDRESS_LIMIT = 100; - -const retryableAxios = axios.create(); -retryableAxios.defaults.raxConfig = { - instance: retryableAxios, - retryDelay: 10 -}; -rax.attach(retryableAxios); - -export const replaceTimestampWithDateTime = obj => { - if (obj.timestamp) { - obj.timestamp = new DateTime(obj.timestamp); - } - - return obj; -}; - -const transformTimestampToDateTime = (responseData) => { - if (Array.isArray(responseData)) { - responseData.forEach(replaceTimestampWithDateTime); - } else { - replaceTimestampWithDateTime(responseData); - } - - return responseData; -}; - -export const nodeApi = (baseUrl) => { - const get = (url, config) => axios.get(baseUrl + url, config); - const retryableGet = (url, config) => retryableAxios.get(baseUrl + url, config); - - return { - version: () => get('/node/version'), - baseTarget: () => get('/consensus/basetarget'), - addresses: { - details: (address) => get(`/addresses/balance/details/${address}`), - assetsBalance: (address) => get(`/assets/balance/${address}`), - aliases: (address) => get(`/alias/by-address/${address}`), - validate: (address) => get(`/addresses/validate/${address}`), - data: (address) => get(`/addresses/data/${address}`), - script: (address) => get(`/addresses/scriptInfo/${address}`) - }, - blocks: { - height: () => get('/blocks/height'), - heightBySignature: (signature) => get(`/blocks/height/${signature}`), - delay: (fromSignature, count) => get(`/blocks/delay/${fromSignature}/${count}`), - at: (height) => get(`/blocks/at/${height}`, { - transformResponse: axios.defaults.transformResponse.concat(transformTimestampToDateTime) - }), - headers: { - last: () => get('/blocks/headers/last', { - transformResponse: axios.defaults.transformResponse.concat(transformTimestampToDateTime) - }), - sequence: (from, to) => get(`/blocks/headers/seq/${from}/${to}`, { - transformResponse: axios.defaults.transformResponse.concat(transformTimestampToDateTime) - }) - } - }, - transactions: { - unconfirmed: () => get('/transactions/unconfirmed'), - utxSize: () => get('/transactions/unconfirmed/size'), - info: id => retryableGet(`/transactions/info/${id}`), - address: (address, limit, after) => { - const top = limit || TRANSACTIONS_BY_ADDRESS_LIMIT; - const config = after ? { - params: { - after - } - } : undefined; - - return get(`/transactions/address/${address}/limit/${top}`, config); - } - }, - aliases: { - address: (alias) => get(`/alias/by-alias/${alias}`) - }, - peers: () => get('/peers/connected'), - }; -}; diff --git a/src/shared/OrderPrice.js b/src/shared/OrderPrice.js deleted file mode 100644 index e7cc356..0000000 --- a/src/shared/OrderPrice.js +++ /dev/null @@ -1,41 +0,0 @@ -import {Decimal} from 'decimal.js'; - -const MATCHER_SCALE = 1e8; - -const roundToPriceAsset = (price, pair) => { - return new Decimal(new Decimal(price).toFixed(pair.priceAsset.precision, Decimal.ROUND_FLOOR)); -}; - -const normalizePrice = (price, pair) => { - return new Decimal(price) - .div(MATCHER_SCALE) - .div(Math.pow(10, pair.priceAsset.precision - pair.amountAsset.precision)); -}; - -class OrderPrice { - constructor(price, pair) { - this.amountAsset = pair.amountAsset; - this.priceAsset = pair.priceAsset; - this.price = roundToPriceAsset(price, pair); - } - - toTokens = () => this.price.toNumber(); - toCoins = () => this.toTokens() * Math.pow(10, this.priceAsset.precision - this.amountAsset.precision); - toBackendPrice = () => Math.round(this.toCoins() * MATCHER_SCALE); - - toString() { - return this.toTokens().toFixed(8); - } -} - -export default { - fromTokens: function (price, pair) { - return new OrderPrice(price, pair); - }, - - fromBackendPrice: function (price, pair) { - var normalizedPrice = normalizePrice(price, pair); - - return new OrderPrice(normalizedPrice, pair); - } -}; diff --git a/src/shared/Routing.js b/src/shared/Routing.js deleted file mode 100644 index 8f44a5a..0000000 --- a/src/shared/Routing.js +++ /dev/null @@ -1,31 +0,0 @@ -export const routeParams = { - blockHeight: ':height', - transactionId: ':transactionId', - address: ':address', - alias: ':alias' -}; - -const blocks = `/blocks`; - -export const routes = { - root: '/', - nodes: { - list: `/nodes` - }, - peers: { - list: `/peers` - }, - blocks: { - list: blocks, - one: (height) => `${blocks}/${height}` - }, - transactions: { - one: (id) => `/tx/${id}` - }, - addresses: { - one: (address) => `/address/${address}` - }, - aliases: { - one: (alias) => `/aliases/${alias}` - } -}; diff --git a/src/shared/ScriptInfo.js b/src/shared/ScriptInfo.js deleted file mode 100644 index 7834952..0000000 --- a/src/shared/ScriptInfo.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import EmptyData from './EmptyData'; - -export default class ScriptInfo extends React.PureComponent { - static propTypes = { - script: PropTypes.string - }; - - render() { - const isEmpty = !this.props.script; - const rowClassName = 'data-container' + (isEmpty ? ' empty' : ''); - - return ( -
- {isEmpty ? :
{this.props.script}
} -
- ); - } -} diff --git a/src/shared/Spacer.js b/src/shared/Spacer.js deleted file mode 100644 index 83e10ab..0000000 --- a/src/shared/Spacer.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -const Spacer = ({size}) => { - return -}; - -export default Spacer; diff --git a/src/shared/ThirdPartyApi.js b/src/shared/ThirdPartyApi.js deleted file mode 100644 index 2aafda7..0000000 --- a/src/shared/ThirdPartyApi.js +++ /dev/null @@ -1,5 +0,0 @@ -import axios from 'axios'; - -export const thirdPartyApi = (antiSpamUrl) => ({ - antispamList: () => axios.get(antiSpamUrl) -}); diff --git a/src/shared/TransactionArrow.js b/src/shared/TransactionArrow.js deleted file mode 100644 index 50c5056..0000000 --- a/src/shared/TransactionArrow.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import {typeToCssClass, TransactionDirections} from '../shared/TransactionDefinitions'; - -const TransactionArrow = ({type, direction}) => { - let className = 'arrow ' + typeToCssClass(type); - if (direction) { - className += ' ' + directionToArrowClass(direction); - } - - return
-}; - -TransactionArrow.propTypes = { - type: PropTypes.number.isRequired, - direction: PropTypes.oneOf([TransactionDirections.INCOMING, TransactionDirections.OUTGOING]) -}; - -const directionToArrowClass = direction => { - switch (direction) { - case TransactionDirections.INCOMING: - return 'in'; - - case TransactionDirections.OUTGOING: - return 'out'; - - default: - return ''; - } -}; - -export default TransactionArrow; diff --git a/src/shared/TransactionBadge.js b/src/shared/TransactionBadge.js deleted file mode 100644 index e1f2e03..0000000 --- a/src/shared/TransactionBadge.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import {typeToCssClass, typeToTitle, directionToCssClass} from '../shared/TransactionDefinitions'; - -const TransactionBadge = ({type, direction}) => { - const className = 'badge ' + typeToCssClass(type) + ' ' + directionToCssClass(direction); - return ( - {typeToTitle(type)} - ); -}; - -TransactionBadge.propTypes = { - type: PropTypes.number.isRequired, - direction: PropTypes.string -}; - -export default TransactionBadge; diff --git a/src/shared/TransactionDefinitions.js b/src/shared/TransactionDefinitions.js deleted file mode 100644 index 798222b..0000000 --- a/src/shared/TransactionDefinitions.js +++ /dev/null @@ -1,55 +0,0 @@ -const TransactionTypes = Object.freeze({ - 2: {title: 'Payment', cssClassName: 'asset-transfer'}, - 3: {title: 'Asset Issue', cssClassName: 'asset-issue'}, - 4: {title: 'Asset Transfer', cssClassName: 'asset-transfer'}, - 5: {title: 'Asset Reissue', cssClassName: 'asset-reissue'}, - 6: {title: 'Asset Burn', cssClassName: 'asset-burn'}, - 7: {title: 'Exchange', cssClassName: 'exchange'}, - 8: {title: 'Lease', cssClassName: 'lease'}, - 9: {title: 'Lease Cancel', cssClassName: 'lease-cancel'}, - 10: {title: 'Create Alias', cssClassName: 'create-alias'}, - 11: {title: 'Mass Payment', cssClassName: 'mass-payment'}, - 12: {title: 'Data', cssClassName: 'data'}, - 13: {title: 'Script', cssClassName: 'script'}, - 14: {title: 'Sponsorship', cssClassName: 'sponsorship'}, -}); - -export const TransactionDirections = { - INCOMING: 'incoming', - OUTGOING: 'outgoing' -}; - -const getMapping = type => { - return TransactionTypes[parseInt(type)]; -}; - -export const typeToCssClass = type => { - const mapping = getMapping(type); - - if (!mapping) - return ''; - - return mapping.cssClassName; -}; - -export const typeToTitle = type => { - const mapping = getMapping(type); - - if (!mapping) - return 'Unknown'; - - return mapping.title; -}; - -export const directionToCssClass = direction => { - switch (direction) { - case TransactionDirections.INCOMING: - return 'in'; - - case TransactionDirections.OUTGOING: - return 'out'; - - default: - return ''; - } -}; diff --git a/src/shared/TransactionRef.js b/src/shared/TransactionRef.js deleted file mode 100644 index ce7e9ed..0000000 --- a/src/shared/TransactionRef.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {Link} from 'react-router-dom'; - -import {routes} from './Routing'; - -class TransactionRef extends React.PureComponent { - static propTypes = { - txId: PropTypes.string.isRequired, - text: PropTypes.string - }; - - render() { - const text = this.props.text || this.props.txId; - - return ({text}); - } -} - -export default TransactionRef; diff --git a/src/shared/constants.js b/src/shared/constants.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/transactions/Description.js b/src/transactions/Description.js deleted file mode 100644 index 44282f3..0000000 --- a/src/transactions/Description.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const Description = ({text}) => { - return {text}; -}; - -Description.propTypes = { - text: PropTypes.string -}; - -Description.defaultProps = { - text: '' -}; - -export default Description; diff --git a/src/transactions/MassPaymentDetails.js b/src/transactions/MassPaymentDetails.js deleted file mode 100644 index 405ed62..0000000 --- a/src/transactions/MassPaymentDetails.js +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import EndpointRef from '../shared/EndpointRef'; - -const TransferListItem = ({transfer}) => { - return ( - - -
- - -
{transfer.amount.toString()}
- - - ); -}; - -TransferListItem.propTypes = { - transfer: PropTypes.shape({ - recipient: PropTypes.string.isRequired, - amount: PropTypes.number.isRequired - }) -}; - -const TransferList = ({transfers}) => { - return ( - - - - - - - - - {transfers.map((item, index) => { - return - })} - -
RecipientAmount
- ); -}; - -TransferList.propTypes = { - transfers: PropTypes.arrayOf(TransferListItem.propTypes.transfer) -}; - -export default class MassPaymentDetails extends React.PureComponent { - static propTypes = { - tx: PropTypes.object.isRequired - }; - - render() { - const {tx} = this.props; - if (tx.type !== 11) - return null; - - return ( - -
- Transfers -
- -
- ); - } -} diff --git a/src/transactions/SingleTransactionPage.js b/src/transactions/SingleTransactionPage.js deleted file mode 100644 index 55efc8b..0000000 --- a/src/transactions/SingleTransactionPage.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; - -import Loader from '../shared/Loader'; -import GoBack from '../shared/GoBack'; -import Headline from '../shared/Headline'; -import Dictionary from '../shared/Dictionary'; -import ServiceFactory from '../services/ServiceFactory'; - -import transactionToDictionary from './TransactionToDictionaryTransformer'; -import MassPaymentDetails from "./MassPaymentDetails"; - -export default class SingleTransactionPage extends React.Component { - state = { - tx: { - id: this.props.match.params.transactionId - } - }; - - componentDidUpdate(prevProps) { - if (this.props.match.params.transactionId !== prevProps.match.params.transactionId) { - this.fetchData(); - } - } - - fetchData = () => { - const {transactionId} = this.props.match.params; - return ServiceFactory.transactionService().loadTransaction(transactionId) - .then(tx => this.setState({tx})); - }; - - render() { - const transactionItems = transactionToDictionary(this.state.tx); - - return ( - - - - - - - - - ); - } -} diff --git a/src/transactions/TransactionToDictionaryTransformer.js b/src/transactions/TransactionToDictionaryTransformer.js deleted file mode 100644 index 05c53cd..0000000 --- a/src/transactions/TransactionToDictionaryTransformer.js +++ /dev/null @@ -1,300 +0,0 @@ -import React from 'react'; - -import EndpointRef from '../shared/EndpointRef'; -import CurrencyRef from '../shared/CurrencyRef'; -import TransactionBadge from '../shared/TransactionBadge'; -import TransactionRef from '../shared/TransactionRef'; -import BlockRef from '../shared/BlockRef'; -import Spacer from '../shared/Spacer'; - -import Description from './Description'; -import ScriptInfo from '../shared/ScriptInfo'; -import DataInfo from '../shared/DataInfo'; - -const transactionToDictionary = (tx) => { - switch (tx.type) { - case 2: - case 4: - return transferTransactionToItems(tx); - - case 3: - return issueTransactionToItems(tx); - - case 5: - return reissueTransactionToItems(tx); - - case 6: - return burnTransactionToItems(tx); - - case 7: - return exchangeTransactionToItems(tx); - - case 8: - return leaseTransactionToItems(tx); - - case 9: - return cancelLeaseTransactionItems(tx); - - case 10: - return aliasTransactionToItems(tx); - - case 11: - return massPaymentTransactionToItems(tx); - - case 12: - return dataTransactionToItems(tx); - - case 13: - return scriptTransactionToItems(tx); - - case 14: - return sponsorshipTransactionToItems(tx); - - default: - return []; - } -}; - -const dataTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - { - label: 'Data', - value: - }, - buildFeeItem(tx), - buildSenderItem(tx) - ]; -}; - -const scriptTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - { - label: 'Script', - value: - }, - buildFeeItem(tx), - buildSenderItem(tx) - ]; -}; - -const sponsorshipTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - { - label: 'Sponsored Fee', - value: tx.sponsoredFee ? tx.sponsoredFee.toString() : 'Cancelled' - }, { - label: 'Transaction Fee', - value: tx.fee.toString() - }, - buildSenderItem(tx) - ]; -}; - -const aliasTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - { - label: 'Alias', - value: - }, - buildFeeItem(tx), - buildSenderItem(tx) - ]; -}; - -const cancelLeaseTransactionItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - { - label: 'Lease', - value: - }, - buildFeeItem(tx), - buildSenderItem(tx) - ]; -}; - -const leaseTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - buildAmountItem(tx), - buildFeeItem(tx), - buildRecipientItem(tx), - buildSenderItem(tx), - { - label: 'Status', - value: tx.status - } - ]; -}; - -const reissueTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - buildQuantityItem(tx), - buildReissuableItem(tx), - buildFeeItem(tx), - buildSenderItem(tx) - ]; -}; - -const issueTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - buildQuantityItem(tx), - { - label: 'Decimals', - value: tx.decimals - }, - buildDescriptionItem(tx), - buildReissuableItem(tx), - buildFeeItem(tx), - buildSenderItem(tx) - ]; -}; - -const burnTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - buildAmountItem(tx), - buildFeeItem(tx) - ]; -}; - -const transferTransactionToItems = tx => { - return [ - ...buildTransactionHeaderItems(tx), - buildRecipientItem(tx), - buildAmountItem(tx), - buildFeeItem(tx), - buildAttachmentItem(tx), - buildSenderItem(tx) - ]; -}; - -const exchangeTransactionToItems = tx => { - const assetPair = tx.buyOrder.assetPair; - - const items = [{ - label: 'Price', - value: tx.price.toString() - }, { - label: 'Total', - value: tx.total.toString() - }]; - - return [ - ...buildTransactionHeaderItems(tx), - buildFeeItem(tx), - buildAmountItem(tx), - ...items, - buildSenderItem(tx), - buildRecipientItem(tx), - { - label: 'Pair', - value: / - }, - ...buildOrderItems(tx.buyOrder), - ...buildOrderItems(tx.sellOrder) - ]; -}; - -const massPaymentTransactionToItems = tx => { - const items = [{ - label: 'Total amount', - value: tx.totalAmount.toString() - }, { - label: 'Transfers count', - value: tx.transferCount, - }]; - - return [ - ...buildTransactionHeaderItems(tx), - ...items, - buildAttachmentItem(tx), - buildFeeItem(tx), - buildSenderItem(tx) - ]; -}; - -const buildOrderItems = order => { - return [{ - label: 'Order Id', - value: order.id - }, { - label: 'Order Type', - value: order.orderType - }, - buildSenderItem(order), - buildAmountItem(order), - { - label: 'Price', - value: order.price.toString() - }, - buildTimestampItem(order.timestamp) - ]; -}; - -const buildDescriptionItem = tx => ({ - label: 'Description', - value: -}); - -const buildAttachmentItem = tx => ({ - label: 'Attachment', - value: -}); - -const buildTimestampItem = timestamp => ({ - label: 'Timestamp', - value: timestamp.toLongString(), -}); - -const buildTransactionHeaderItems = tx => { - return [{ - label: 'Type', - value: {tx.type} - }, buildTimestampItem(tx.timestamp), { - label: 'Block', - value: - }]; -}; - -const buildQuantityItem = tx => ({ - label: 'Quantity', - value: tx.amount.toString() -}); - -const buildReissuableItem = tx => ({ - label: 'Reissuable', - value: (!!tx.reissuable).toString() -}); - -const buildRecipientItem = tx => ({ - label: 'Recipient', - value: -}); - -const buildSenderItem = tx => ({ - label: 'Sender', - value: -}); - -const buildFeeItem = tx => ({ - label: 'Fee', - value: setAcryl(tx.fee.toString()) -}); - -const buildAmountItem = tx => ({ - label: 'Amount', - value: setAcryl(tx.amount.toString()) -}); - -const setAcryl = str => { - return str.includes('WAVES') ? str.replace('WAVES', 'ACRYL') : str; -} - -export default transactionToDictionary;