Browse Source

Merge pull request #60 from LN-Zap/feature/refresh-data

Feature/refresh data
renovate/lint-staged-8.x
JimmyMow 7 years ago
committed by GitHub
parent
commit
8242749293
  1. 6
      app/api/index.js
  2. 6
      app/app.global.scss
  3. 144
      app/components/Channels/Channels.js
  4. 24
      app/components/Channels/Channels.scss
  5. 30
      app/components/LndSyncing/LndSyncing.js
  6. 73
      app/components/Peers/Peers.js
  7. 14
      app/components/Peers/Peers.scss
  8. 10
      app/keyframes.scss
  9. 4
      app/lnd/index.js
  10. 1
      app/lnd/lib/lightning.js
  11. 2
      app/lnd/subscribe/index.js
  12. 2
      app/reducers/balance.js
  13. 2
      app/reducers/ipc.js
  14. 12
      app/reducers/lnd.js
  15. 3
      app/reducers/transaction.js
  16. 11
      app/routes/app/components/App.js
  17. 4
      app/routes/wallet/components/Wallet.js

6
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)
}
}

6
app/app.global.scss

@ -66,4 +66,10 @@ body {
opacity: 1;
stroke: darken($main, 10%);
}
}
@keyframes spin {
100% {
transform: rotate(360deg);
}
}

144
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
}) => (
<div className={styles.channels}>
<ChannelModal
isOpen={channelModalOpen}
resetChannel={setChannel}
channel={modalChannel}
explorerLinkBase={explorerLinkBase}
closeChannel={closeChannel}
/>
<ChannelForm form={channelForm} setForm={setChannelForm} ticker={ticker} peers={peers} openChannel={openChannel} currentTicker={currentTicker} />
<div className={styles.header}>
<h3>Channels</h3>
<div
className={`${styles.openChannel} hint--top`}
data-hint='Open a channel'
onClick={() => setChannelForm({ isOpen: true })}
>
<TiPlus />
}) => {
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 (
<div className={styles.channels}>
<ChannelModal
isOpen={channelModalOpen}
resetChannel={setChannel}
channel={modalChannel}
explorerLinkBase={explorerLinkBase}
closeChannel={closeChannel}
/>
<ChannelForm
form={channelForm}
setForm={setChannelForm}
ticker={ticker}
peers={peers}
openChannel={openChannel}
currentTicker={currentTicker}
/>
<div className={styles.header}>
<h3>Channels</h3>
<span
className={`${styles.refresh} hint--top`}
data-hint='Refresh your channels list'
>
<FaRepeat
style={{ verticalAlign: 'baseline' }}
onClick={refreshClicked}
/>
</span>
<div
className={`${styles.openChannel} hint--top`}
data-hint='Open a channel'
onClick={() => setChannelForm({ isOpen: true })}
>
<TiPlus />
</div>
</div>
</div>
<ul>
{
!channelsLoading ?
allChannels.map((channel, index) => {
if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) {
<ul>
{
!channelsLoading ?
allChannels.map((channel, index) => {
if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) {
return (
<OpenPendingChannel
key={index}
channel={channel}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={explorerLinkBase}
/>
)
} else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) {
return (
<ClosedPendingChannel
key={index}
channel={channel}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={explorerLinkBase}
/>
)
}
return (
<OpenPendingChannel
key={index}
channel={channel}
<Channel
key={channel.chan_id}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={explorerLinkBase}
/>
)
} else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) {
return (
<ClosedPendingChannel
key={index}
channel={channel}
ticker={ticker}
setChannel={setChannel}
currentTicker={currentTicker}
explorerLinkBase={explorerLinkBase}
/>
)
}
return (
<Channel
key={channel.chan_id}
ticker={ticker}
channel={channel}
setChannel={setChannel}
currentTicker={currentTicker}
/>
)
})
:
'Loading...'
}
</ul>
</div>
)
})
:
'Loading...'
}
</ul>
</div>
)
}
Channels.propTypes = {
fetchChannels: PropTypes.func.isRequired,
ticker: PropTypes.object.isRequired,
peers: PropTypes.array.isRequired,
channelsLoading: PropTypes.bool.isRequired,

24
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;

30
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 {
<h3>zap</h3>
<div className={styles.loading}>
{!fetchingBlockHeight && <h4>{syncPercentage}%</h4>}
<div className={styles.spinner}>
</div>
<div className={styles.spinner} />
<h1>syncing your lightning node to the blockchain</h1>
</div>
<div className={styles.facts}>
@ -52,15 +52,13 @@ class LndSyncing extends Component {
</div>
<ul>
{
facts.map((facts, index) => {
return (
<li
className={`${styles.factButton} ${currentFact === index && styles.active}`}
key={index}
onClick={() => this.setState({ currentFact: index })}
/>
)
})
facts.map((fact, index) => (
<li
className={`${styles.factButton} ${currentFact === index && styles.active}`}
key={index}
onClick={() => this.setState({ currentFact: index })}
/>
))
}
</ul>
</div>
@ -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

73
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
}) => (
<div className={styles.peers}>
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} />
<PeerForm form={peerForm} setForm={setPeerForm} connect={connect} />
<div className={styles.header}>
<h3>Peers</h3>
<div
className={`${styles.connectPeer} hint--top`}
data-hint='Connect to a peer'
onClick={() => setPeerForm({ isOpen: true })}
>
<TiPlus />
}) => {
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 (
<div className={styles.peers}>
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} />
<PeerForm form={peerForm} setForm={setPeerForm} connect={connect} />
<div className={styles.header}>
<h3>Peers</h3>
<span
className={`${styles.refresh} hint--top`}
data-hint='Refresh your peers list'
>
<FaRepeat
style={{ verticalAlign: 'baseline' }}
onClick={refreshClicked}
/>
</span>
<div
className={`${styles.connectPeer} hint--top`}
data-hint='Connect to a peer'
onClick={() => setPeerForm({ isOpen: true })}
>
<TiPlus />
</div>
</div>
<ul>
{
!peersLoading ?
peers.map(peer => <Peer key={peer.peer_id} peer={peer} setPeer={setPeer} />)
:
'Loading...'
}
</ul>
</div>
<ul>
{
!peersLoading ?
peers.map(peer => <Peer key={peer.peer_id} peer={peer} setPeer={setPeer} />)
:
'Loading...'
}
</ul>
</div>
)
)
}
Peers.propTypes = {
fetchPeers: PropTypes.func.isRequired,
peersLoading: PropTypes.bool.isRequired,
peers: PropTypes.array.isRequired,
setPeer: PropTypes.func.isRequired,

14
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;

10
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);
}
}

4
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)
}
}

1
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)

2
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)
}

2
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 })
}

2
app/reducers/ipc.js

@ -36,7 +36,7 @@ const ipc = createIpc({
lndSyncing,
lndSynced,
lndStdout,
receiveInfo,
receivePeers,

12
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 })
}
// ------------------------------------

3
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

11
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 <LoadingBolt /> }
@ -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,

4
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 {
</section>
<section className={styles.walletData}>
<Peers
fetchPeers={fetchPeers}
peersLoading={peersLoading}
peers={peers}
modalPeer={peer}
@ -64,6 +67,7 @@ class Wallet extends Component {
disconnect={disconnectRequest}
/>
<Channels
fetchChannels={fetchChannels}
ticker={ticker}
peers={peers}
channelsLoading={channelsLoading}

Loading…
Cancel
Save