diff --git a/app/api/index.js b/app/api/index.js index e71c69df..d394fe60 100644 --- a/app/api/index.js +++ b/app/api/index.js @@ -16,12 +16,12 @@ export function requestTickers(ids) { } -export function requestBlockHeight(id) { - const BASE_URL = `https://testnet-api.smartbit.com.au/v1/blockchain/blocks?limit=1` +export function requestBlockHeight() { + const BASE_URL = 'https://testnet-api.smartbit.com.au/v1/blockchain/blocks?limit=1' return axios({ method: 'get', url: BASE_URL }) .then(response => response.data) .catch(error => error) -} \ No newline at end of file +} diff --git a/app/app.global.scss b/app/app.global.scss index d55b7f23..0a946033 100644 --- a/app/app.global.scss +++ b/app/app.global.scss @@ -66,4 +66,10 @@ body { opacity: 1; stroke: darken($main, 10%); } +} + +@keyframes spin { + 100% { + transform: rotate(360deg); + } } \ No newline at end of file diff --git a/app/components/Channels/Channels.js b/app/components/Channels/Channels.js index 18c73cee..012190e4 100644 --- a/app/components/Channels/Channels.js +++ b/app/components/Channels/Channels.js @@ -1,6 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' import { TiPlus } from 'react-icons/lib/ti' +import { FaRepeat } from 'react-icons/lib/fa' import ChannelModal from './ChannelModal' import ChannelForm from './ChannelForm' import Channel from './Channel' @@ -9,6 +10,7 @@ import ClosedPendingChannel from './ClosedPendingChannel' import styles from './Channels.scss' const Channels = ({ + fetchChannels, ticker, peers, channelsLoading, @@ -22,69 +24,103 @@ const Channels = ({ closeChannel, currentTicker, explorerLinkBase -}) => ( -
- - -
-

Channels

-
setChannelForm({ isOpen: true })} - > - +}) => { + const refreshClicked = (event) => { + // store event in icon so we dont get an error when react clears it + const icon = event.currentTarget + + // fetch channels + fetchChannels() + + // clear animation after the second so we can reuse it + setTimeout(() => { icon.style.animation = '' }, 1000) + + // spin icon for 1 sec + icon.style.animation = 'spin 1000ms linear 1' + } + + return ( +
+ + +
+

Channels

+ + + +
setChannelForm({ isOpen: true })} + > + +
-
-
    - { - !channelsLoading ? - allChannels.map((channel, index) => { - if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) { +
      + { + !channelsLoading ? + allChannels.map((channel, index) => { + if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) { + return ( + + ) + } else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) { + return ( + + ) + } return ( - - ) - } else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) { - return ( - ) - } - return ( - - ) - }) - : - 'Loading...' - } -
    -
-) + }) + : + 'Loading...' + } + +
+ ) +} Channels.propTypes = { + fetchChannels: PropTypes.func.isRequired, ticker: PropTypes.object.isRequired, peers: PropTypes.array.isRequired, channelsLoading: PropTypes.bool.isRequired, diff --git a/app/components/Channels/Channels.scss b/app/components/Channels/Channels.scss index 8d73c905..df5f7b38 100644 --- a/app/components/Channels/Channels.scss +++ b/app/components/Channels/Channels.scss @@ -1,5 +1,15 @@ @import '../../variables.scss'; +@keyframes spin { + from { + transform: rotate(0deg) + } + + to { + transform: rotate(360deg); + } +} + .channels { width: 75%; margin: 50px auto; @@ -15,6 +25,20 @@ text-align: left; } + .refresh { + cursor: pointer; + margin-left: 5px; + font-size: 12px; + vertical-align: top; + color: $darkestgrey; + line-height: 14px; + transition: color 0.25s; + + &:hover { + color: $main; + } + } + .openChannel { float: right; cursor: pointer; diff --git a/app/components/LndSyncing/LndSyncing.js b/app/components/LndSyncing/LndSyncing.js index 43acbde1..eff73e6a 100644 --- a/app/components/LndSyncing/LndSyncing.js +++ b/app/components/LndSyncing/LndSyncing.js @@ -1,14 +1,15 @@ import React, { Component } from 'react' +import PropTypes from 'prop-types' import styles from './LndSyncing.scss' class LndSyncing extends Component { constructor(props) { - super(props); + super(props); this.state = { facts: [ { title: 'No2x', - description: 'Segwit2x is a hard fork proposal led by Barry Silbert and the NYA signers. The idea was drawn up and signed in a locked hotel room with select individuals and goes against everything that Bitcoin stands for. There is no favoritism in Bitcoin. There are no politicians. Hash power and business don\'t speak for us. Don\'t trust, verify.' + description: 'Segwit2x is a hard fork proposal led by Barry Silbert and the NYA signers. The idea was drawn up and signed in a locked hotel room with select individuals and goes against everything that Bitcoin stands for. There is no favoritism in Bitcoin. There are no politicians. Hash power and business don\'t speak for us. Don\'t trust, verify.' // eslint-disable-line }, { title: 'Gang', @@ -41,8 +42,7 @@ class LndSyncing extends Component {

zap

{!fetchingBlockHeight &&

{syncPercentage}%

} -
-
+

syncing your lightning node to the blockchain

@@ -52,15 +52,13 @@ class LndSyncing extends Component {
    { - facts.map((facts, index) => { - return ( -
  • this.setState({ currentFact: index })} - /> - ) - }) + facts.map((fact, index) => ( +
  • this.setState({ currentFact: index })} + /> + )) }
@@ -69,4 +67,10 @@ class LndSyncing extends Component { } } +LndSyncing.propTypes = { + fetchBlockHeight: PropTypes.func.isRequired, + fetchingBlockHeight: PropTypes.bool.isRequired, + syncPercentage: PropTypes.number.isRequired +} + export default LndSyncing diff --git a/app/components/Peers/Peers.js b/app/components/Peers/Peers.js index 5df2b11e..45115cec 100644 --- a/app/components/Peers/Peers.js +++ b/app/components/Peers/Peers.js @@ -1,12 +1,14 @@ import React from 'react' import PropTypes from 'prop-types' import { TiPlus } from 'react-icons/lib/ti' +import { FaRepeat } from 'react-icons/lib/fa' import PeerModal from './PeerModal' import PeerForm from './PeerForm' import Peer from './Peer' import styles from './Peers.scss' const Peers = ({ + fetchPeers, peersLoading, peers, setPeer, @@ -16,32 +18,59 @@ const Peers = ({ setPeerForm, connect, disconnect -}) => ( -
- - -
-

Peers

-
setPeerForm({ isOpen: true })} - > - +}) => { + const refreshClicked = (event) => { + // store event in icon so we dont get an error when react clears it + const icon = event.currentTarget + + // fetch peers + fetchPeers() + + // clear animation after the second so we can reuse it + setTimeout(() => { icon.style.animation = '' }, 1000) + + // spin icon for 1 sec + icon.style.animation = 'spin 1000ms linear 1' + } + + return ( +
+ + +
+

Peers

+ + + +
setPeerForm({ isOpen: true })} + > + +
+
    + { + !peersLoading ? + peers.map(peer => ) + : + 'Loading...' + } +
-
    - { - !peersLoading ? - peers.map(peer => ) - : - 'Loading...' - } -
-
-) + ) +} Peers.propTypes = { + fetchPeers: PropTypes.func.isRequired, peersLoading: PropTypes.bool.isRequired, peers: PropTypes.array.isRequired, setPeer: PropTypes.func.isRequired, diff --git a/app/components/Peers/Peers.scss b/app/components/Peers/Peers.scss index f24f6f70..613ce641 100644 --- a/app/components/Peers/Peers.scss +++ b/app/components/Peers/Peers.scss @@ -15,6 +15,20 @@ text-align: left; } + .refresh { + cursor: pointer; + margin-left: 5px; + font-size: 12px; + vertical-align: top; + color: $darkestgrey; + line-height: 14px; + transition: color 0.25s; + + &:hover { + color: $main; + } + } + .connectPeer { float: right; cursor: pointer; diff --git a/app/keyframes.scss b/app/keyframes.scss index a5cc3fe8..c5317b88 100644 --- a/app/keyframes.scss +++ b/app/keyframes.scss @@ -30,4 +30,14 @@ 50% { color: $white; } 75% { color: $gold; } 100% { color: $white; } +} + +@keyframes spin { + from { + transform:rotate(0deg) + } + + to { + transform:rotate(360deg); + } } \ No newline at end of file diff --git a/app/lnd/index.js b/app/lnd/index.js index cb8d8a03..ef0d3623 100644 --- a/app/lnd/index.js +++ b/app/lnd/index.js @@ -5,9 +5,9 @@ import methods from './methods' export default (callback) => { const lnd = lightning(config.lightningRpc, config.lightningHost) - + const lndSubscribe = mainWindow => subscribe(mainWindow, lnd) const lndMethods = (event, msg, data) => methods(lnd, event, msg, data) callback(lndSubscribe, lndMethods) -} \ No newline at end of file +} diff --git a/app/lnd/lib/lightning.js b/app/lnd/lib/lightning.js index 3c3a30f8..5af4443a 100644 --- a/app/lnd/lib/lightning.js +++ b/app/lnd/lib/lightning.js @@ -5,7 +5,6 @@ import config from '../config' module.exports = (rpcpath, host) => { process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA' - console.log('RPC PATH: ', path.join(__dirname, 'rpc.proto')) const rpc = grpc.load(path.join(__dirname, 'rpc.proto')) const lndCert = fs.readFileSync(config.cert) diff --git a/app/lnd/subscribe/index.js b/app/lnd/subscribe/index.js index ae1f08f5..170adf60 100644 --- a/app/lnd/subscribe/index.js +++ b/app/lnd/subscribe/index.js @@ -2,8 +2,6 @@ import subscribeToTransactions from './transactions' import subscribeToInvoices from './invoices' export default (mainWindow, lnd) => { - console.log('mainWindow: ', mainWindow) - console.log('lnd: ', lnd) subscribeToTransactions(mainWindow, lnd) subscribeToInvoices(mainWindow, lnd) } diff --git a/app/reducers/balance.js b/app/reducers/balance.js index 4b1b458e..4da402fe 100644 --- a/app/reducers/balance.js +++ b/app/reducers/balance.js @@ -21,7 +21,7 @@ export const fetchBalance = () => async (dispatch) => { } // Receive IPC event for balance -export const receiveBalance = (event, { walletBalance, channelBalance }) => dispatch => { +export const receiveBalance = (event, { walletBalance, channelBalance }) => (dispatch) => { dispatch({ type: RECEIVE_BALANCE, walletBalance, channelBalance }) } diff --git a/app/reducers/ipc.js b/app/reducers/ipc.js index d8329d1b..a0789e30 100644 --- a/app/reducers/ipc.js +++ b/app/reducers/ipc.js @@ -36,7 +36,7 @@ const ipc = createIpc({ lndSyncing, lndSynced, lndStdout, - + receiveInfo, receivePeers, diff --git a/app/reducers/lnd.js b/app/reducers/lnd.js index 613db848..0c237775 100644 --- a/app/reducers/lnd.js +++ b/app/reducers/lnd.js @@ -22,7 +22,7 @@ export const RECEIVE_BLOCK_HEIGHT = 'RECEIVE_BLOCK_HEIGHT' export const lndSyncing = () => dispatch => dispatch({ type: START_SYNCING }) // Receive IPC event for LND stoping sync -export const lndSynced = () => dispatch => { +export const lndSynced = () => (dispatch) => { // Fetch data now that we know LND is synced dispatch(fetchTicker()) dispatch(fetchBalance()) @@ -32,7 +32,9 @@ export const lndSynced = () => dispatch => { } // Receive IPC event for LND streaming a line -export const lndStdout = (event, lndBlockHeight) => dispatch => dispatch({ type: RECEIVE_LINE, lndBlockHeight: lndBlockHeight.split(' ')[0].split(/(\r\n|\n|\r)/gm)[0] }) +export const lndStdout = (event, lndBlockHeight) => dispatch => ( + dispatch({ type: RECEIVE_LINE, lndBlockHeight: lndBlockHeight.split(' ')[0].split(/(\r\n|\n|\r)/gm)[0] }) +) export function getBlockHeight() { return { @@ -60,11 +62,11 @@ export const fetchBlockHeight = () => async (dispatch) => { const ACTION_HANDLERS = { [START_SYNCING]: state => ({ ...state, syncing: true }), [STOP_SYNCING]: state => ({ ...state, syncing: false }), - + [RECEIVE_LINE]: (state, { lndBlockHeight }) => ({ ...state, lndBlockHeight }), - + [GET_BLOCK_HEIGHT]: state => ({ ...state, fetchingBlockHeight: true }), - [RECEIVE_BLOCK_HEIGHT]: (state, { blockHeight }) => ({ ...state, blockHeight, fetchingBlockHeight: false }), + [RECEIVE_BLOCK_HEIGHT]: (state, { blockHeight }) => ({ ...state, blockHeight, fetchingBlockHeight: false }) } // ------------------------------------ diff --git a/app/reducers/transaction.js b/app/reducers/transaction.js index cd305ffc..33821551 100644 --- a/app/reducers/transaction.js +++ b/app/reducers/transaction.js @@ -73,10 +73,9 @@ export const transactionError = () => (dispatch) => { // Listener for when a new transaction is pushed from the subscriber export const newTransaction = (event, { transaction }) => (dispatch) => { - console.log('transaction: ', transaction) // Fetch new balance dispatch(fetchBalance()) - + dispatch({ type: ADD_TRANSACTION, transaction }) // HTML 5 desktop notification for the new transaction diff --git a/app/routes/app/components/App.js b/app/routes/app/components/App.js index 837bba83..43df072d 100644 --- a/app/routes/app/components/App.js +++ b/app/routes/app/components/App.js @@ -11,10 +11,6 @@ class App extends Component { componentWillMount() { const { fetchTicker, fetchBalance, fetchInfo, lnd: { syncing } } = this.props - if (syncing) { - fetchBlockHeight() - } - if (!syncing) { fetchTicker() fetchBalance() @@ -51,7 +47,7 @@ class App extends Component { fetchingBlockHeight={lnd.fetchingBlockHeight} syncPercentage={syncPercentage} /> - ) + ) } if (!currentTicker) { return } @@ -86,6 +82,11 @@ class App extends Component { } App.propTypes = { + lnd: PropTypes.object.isRequired, + + syncPercentage: PropTypes.number.isRequired, + fetchBlockHeight: PropTypes.func.isRequired, + modal: PropTypes.object.isRequired, ticker: PropTypes.object.isRequired, balance: PropTypes.object.isRequired, diff --git a/app/routes/wallet/components/Wallet.js b/app/routes/wallet/components/Wallet.js index e21cbe02..07bc1a09 100644 --- a/app/routes/wallet/components/Wallet.js +++ b/app/routes/wallet/components/Wallet.js @@ -21,6 +21,8 @@ class Wallet extends Component { ticker, peers: { peersLoading, peers, peer, peerForm }, channels: { channelsLoading, channels, channel, channelForm, pendingChannels }, + fetchPeers, + fetchChannels, setPeer, setChannel, peerModalOpen, @@ -53,6 +55,7 @@ class Wallet extends Component {