diff --git a/.eslintrc b/.eslintrc index c67c328e..096e0b74 100644 --- a/.eslintrc +++ b/.eslintrc @@ -11,7 +11,7 @@ }, "rules": { "comma-dangle": ["error", "never"], - "semi": 0, + "semi": ["error", "never"], "indent": 2, "jsx-quotes": ["error", "prefer-single"], "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], diff --git a/.gitignore b/.gitignore index a06db9c9..f40da82d 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,6 @@ main.js.map .idea npm-debug.log.* + +# lnd binary +resources/bin/* \ No newline at end of file diff --git a/README.md b/README.md index 0805eec1..fb43c16f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,18 @@ $ cd zap-desktop $ yarn $ npm run install-grpc ``` +Zap does not store `lnd` binaries in the Github repo so you will now need to go [install lnd](https://github.com/lightningnetwork/lnd/blob/master/docs/INSTALL.md). You can then copy the `lnd` binary that will be located in your `$GOPATH/bin` and paste it into Zap. Zap expectes `lnd` to be in one of these directories depending on your OS: + +``` +# mac +resources/bin/darwin + +#linux +resources/bin/linux + +#win32 +resources/bin/win32 +``` Then to start it: ```bash @@ -53,7 +65,7 @@ $ npm run lint Please see the [contributing guide](https://github.com/LN-Zap/zap-desktop/blob/master/CONTRIBUTING.md) ## Todos (Last updated August 16th): -Join us on [slack](https://join.slack.com/t/zaphq/shared_invite/enQtMjYzNDQyMTQxOTU4LTY3ZDk4M2Y3YmEzOTM1ODk1NjEwYjJmMmY3NmU2YTM3ZmJmOTViODcxN2E3MmYyNjAxOGNmNzY1ZDhhYmEwMDI) before tackling a todo to avoid duplicate work. +Join us on [slack](https://join.slack.com/t/zaphq/shared_invite/enQtMjc5Njg3NjU5MzMzLWE1M2RiNjYxNWEyMTRjMzhmZDIyNTQ0YTRjNDg4MWNiMzI1ODNlODhhMzE5ZWVmMGVkOWVkMTVmNzBhNDhiZjQ) before tackling a todo to avoid duplicate work. The old todo list was recently removed. Come on slack or check open Github issues to see what contributions are needed. diff --git a/app/app.global.scss b/app/app.global.scss index 93dcdb57..85870d37 100644 --- a/app/app.global.scss +++ b/app/app.global.scss @@ -86,7 +86,8 @@ body { padding-bottom: 15px; border-radius: 2px; text-align: center; - font-size: 18px; + font-size: 16px; + letter-spacing: 1.5px; transition: none; position: relative; color: white; diff --git a/app/components/ChannelForm/StepOne.js b/app/components/ChannelForm/StepOne.js index 0a92df0e..b7aac4e1 100644 --- a/app/components/ChannelForm/StepOne.js +++ b/app/components/ChannelForm/StepOne.js @@ -5,7 +5,7 @@ import styles from './StepOne.scss' class StepOne extends Component { constructor(props) { - super(props); + super(props) this.state = { peers: props.peers, searchQuery: '' diff --git a/app/components/Channels/Channel.scss b/app/components/Channels/Channel.scss index e7eefe52..e985cf8e 100644 --- a/app/components/Channels/Channel.scss +++ b/app/components/Channels/Channel.scss @@ -2,15 +2,17 @@ .channel { position: relative; - background: $lightgrey; + background: $white; margin: 5px 0; padding: 10px; border-top: 1px solid $white; cursor: pointer; transition: all 0.25s; + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); &:hover { opacity: 0.75; + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); } &:first-child { diff --git a/app/components/Channels/OpenPendingChannel.js b/app/components/Channels/OpenPendingChannel.js index ea46fad2..523e1a86 100644 --- a/app/components/Channels/OpenPendingChannel.js +++ b/app/components/Channels/OpenPendingChannel.js @@ -4,17 +4,20 @@ import PropTypes from 'prop-types' import { btc } from 'utils' import styles from './OpenPendingChannel.scss' -const OpenPendingChannel = ({ ticker, channel: { channel }, currentTicker, explorerLinkBase }) => ( -
  • shell.openExternal(`${explorerLinkBase}/tx/${channel.channel_point.split(':')[0]}`)}> -

    Opening Channel...

    +const OpenPendingChannel = ({ ticker, channel, currentTicker, explorerLinkBase }) => ( +
  • shell.openExternal(`${explorerLinkBase}/tx/${channel.channel.channel_point.split(':')[0]}`)}> +
    +

    Opening Channel...

    + Blocks till open: {channel.blocks_till_open} +
    Remote Pubkey -

    {channel.remote_node_pub}

    +

    {channel.channel.remote_node_pub}

    Channel Point -

    {channel.channel_point}

    +

    {channel.channel.channel_point}

    @@ -23,9 +26,9 @@ const OpenPendingChannel = ({ ticker, channel: { channel }, currentTicker, explo

    { ticker.currency === 'btc' ? - btc.satoshisToBtc(channel.capacity) + btc.satoshisToBtc(channel.channel.capacity) : - btc.satoshisToUsd(channel.capacity, currentTicker.price_usd) + btc.satoshisToUsd(channel.channel.capacity, currentTicker.price_usd) }

    @@ -34,9 +37,9 @@ const OpenPendingChannel = ({ ticker, channel: { channel }, currentTicker, explo

    { ticker.currency === 'btc' ? - btc.satoshisToBtc(channel.local_balance) + btc.satoshisToBtc(channel.channel.local_balance) : - btc.satoshisToUsd(channel.local_balance, currentTicker.price_usd) + btc.satoshisToUsd(channel.channel.local_balance, currentTicker.price_usd) }

    Local @@ -45,9 +48,9 @@ const OpenPendingChannel = ({ ticker, channel: { channel }, currentTicker, explo

    { ticker.currency === 'btc' ? - btc.satoshisToBtc(channel.remote_balance) + btc.satoshisToBtc(channel.channel.remote_balance) : - btc.satoshisToUsd(channel.remote_balance, currentTicker.price_usd) + btc.satoshisToUsd(channel.channel.remote_balance, currentTicker.price_usd) }

    Remote diff --git a/app/components/Channels/OpenPendingChannel.scss b/app/components/Channels/OpenPendingChannel.scss index a191915e..6378d213 100644 --- a/app/components/Channels/OpenPendingChannel.scss +++ b/app/components/Channels/OpenPendingChannel.scss @@ -13,14 +13,21 @@ opacity: 0.5; .pending { - color: $main; position: absolute; top: 0; left: 10px; padding: 10px; text-transform: uppercase; font-weight: bold; - font-size: 10px; + + h1 { + color: $main; + font-size: 10px; + } + + span { + font-size: 8px; + } } &:first-child { @@ -30,7 +37,7 @@ .left, .right { padding: 0 10px; margin-bottom: 5; - margin-top: 25px; + margin-top: 40px; section { margin-bottom: 20px; diff --git a/app/components/LndSyncing/LndSyncing.js b/app/components/LndSyncing/LndSyncing.js index 176a9c27..09d35047 100644 --- a/app/components/LndSyncing/LndSyncing.js +++ b/app/components/LndSyncing/LndSyncing.js @@ -4,7 +4,7 @@ import styles from './LndSyncing.scss' class LndSyncing extends Component { constructor(props) { - super(props); + super(props) this.state = { facts: [ { diff --git a/app/components/Peers/PeerModal.js b/app/components/Peers/PeerModal.js index ed578209..1d6ea161 100644 --- a/app/components/Peers/PeerModal.js +++ b/app/components/Peers/PeerModal.js @@ -1,6 +1,9 @@ import React from 'react' import PropTypes from 'prop-types' + import ReactModal from 'react-modal' +import { MdClose } from 'react-icons/lib/md' + import styles from './PeerModal.scss' const PeerModal = ({ isOpen, resetPeer, peer, disconnect }) => { @@ -16,7 +19,8 @@ const PeerModal = ({ isOpen, resetPeer, peer, disconnect }) => { bottom: 'auto', width: '40%', margin: '50px auto', - padding: '40px' + borderRadius: 'none', + padding: '0' } } @@ -30,32 +34,35 @@ const PeerModal = ({ isOpen, resetPeer, peer, disconnect }) => { parentSelector={() => document.body} style={customStyles} > +
    + resetPeer(null)}> + + +
    { - peer ? -
    -
    -

    {peer.address}

    -

    {peer.pub_key}

    -
    + peer && +
    +
    +

    {peer.address}

    +

    {peer.pub_key}

    +
    -
    -
    -
    Satoshis Received
    -
    {peer.sat_recv}
    -
    Satoshis Sent
    -
    {peer.sat_sent}
    -
    Bytes Received
    -
    {peer.bytes_recv}
    -
    Bytes Sent
    -
    {peer.bytes_sent}
    -
    -
    -
    disconnect({ pubkey: peer.pub_key })}> -
    Disconnect peer
    -
    +
    +
    +
    Satoshis Received
    +
    {peer.sat_recv}
    +
    Satoshis Sent
    +
    {peer.sat_sent}
    +
    Bytes Received
    +
    {peer.bytes_recv}
    +
    Bytes Sent
    +
    {peer.bytes_sent}
    +
    +
    +
    disconnect({ pubkey: peer.pub_key })}> +
    Disconnect peer
    - : - null +
    } ) diff --git a/app/components/Peers/PeerModal.scss b/app/components/Peers/PeerModal.scss index e1d41492..91ae0086 100644 --- a/app/components/Peers/PeerModal.scss +++ b/app/components/Peers/PeerModal.scss @@ -1,29 +1,39 @@ @import '../../variables.scss'; -.peer { - padding: 40px; +.closeContainer { + background: $lightgrey; + text-align: right; + padding: 10px; + + span { + color: $darkestgrey; + font-size: 20px; + cursor: pointer; + } } .header { - margin-bottom: 50px; + background: $lightgrey; + padding: 20px; h1 { color: $black; text-align: center; - margin-bottom: 5px; + margin-bottom: 20px; font-weight: bold; } h2 { color: $darkestgrey; - font-size: 14px; + font-size: 12px; text-align: center; } } .details { - width: 75%; - margin: 20px auto; + dl { + padding: 40px 40px 40px 40px; + } dt { text-align: left; @@ -38,36 +48,28 @@ dd { text-align: right; font-weight: 400; - padding: 19px 0; + padding: 30px 0 10px 0; margin-left: 0; - border-top: 1px solid $darkgrey; + border-bottom: 1px solid $darkgrey; } } .close { text-align: center; + padding-bottom: 40px; div { - width: 35%; margin: 0 auto; cursor: pointer; - height: 55px; - min-height: 55px; - text-transform: none; font-size: 18px; - transition: opacity .2s ease-out; - background: $red; - color: $white; + color: $red; border: none; - font-weight: 500; padding: 0; text-align: center; - line-height: 55px; transition: all 0.25s; - border-radius: 5px; &:hover { - background: darken($red, 10%); + color: lighten($red, 10%); } } } diff --git a/app/components/Wallet/ReceiveModal.js b/app/components/Wallet/ReceiveModal.js index 761f4e36..10612aac 100644 --- a/app/components/Wallet/ReceiveModal.js +++ b/app/components/Wallet/ReceiveModal.js @@ -4,9 +4,11 @@ import ReactModal from 'react-modal' import copy from 'copy-to-clipboard' import QRCode from 'qrcode.react' import { showNotification } from 'notifications' +import { MdClose } from 'react-icons/lib/md' +import { FaCopy } from 'react-icons/lib/fa' import styles from './ReceiveModal.scss' -const ReceiveModal = ({ isOpen, hideActivityModal, pubkey, address, newAddress }) => { +const ReceiveModal = ({ isOpen, hideActivityModal, pubkey, address, newAddress, qrCodeType, changeQrCode }) => { const customStyles = { overlay: { cursor: 'pointer' @@ -16,8 +18,10 @@ const ReceiveModal = ({ isOpen, hideActivityModal, pubkey, address, newAddress } left: '20%', right: '0', bottom: 'auto', - width: '60%', - margin: '50px auto' + width: '40%', + margin: '50px auto', + borderRadius: 'none', + padding: '0' } } @@ -36,22 +40,48 @@ const ReceiveModal = ({ isOpen, hideActivityModal, pubkey, address, newAddress } parentSelector={() => document.body} style={customStyles} > +
    + hideActivityModal()}> + + +
    +
    -
    -

    Node Public Key ( copyOnClick(pubkey)}>Copy)

    -

    {pubkey}

    -
    +
    +
    + +
    +
      +
    • + Wallet address +
    • +
    • + Node pubkey +
    • +
    +
    -

    Deposit Address ( copyOnClick(address)}>Copy)

    - newAddress('p2pkh')}>New Address +

    Deposit Address

    + newAddress('np2wkh')}>New Address
    -

    {address}

    +

    + {address} + copyOnClick(address)} className='hint--left' data-hint='Copy address'> + + +

    +
    -
    - -
    +
    +

    Node Public Key

    +

    + {pubkey} + copyOnClick(pubkey)} className='hint--left' data-hint='Copy pubkey'> + + +

    diff --git a/app/components/Wallet/ReceiveModal.scss b/app/components/Wallet/ReceiveModal.scss index 50c32dc6..b2485f66 100644 --- a/app/components/Wallet/ReceiveModal.scss +++ b/app/components/Wallet/ReceiveModal.scss @@ -1,15 +1,59 @@ @import '../../variables.scss'; +.closeContainer { + background: $lightgrey; + text-align: right; + padding: 10px; + + span { + color: $darkestgrey; + font-size: 20px; + cursor: pointer; + } +} + .container { + header { + background: $lightgrey; + padding: 10px 40px 40px; + text-align: center; + + .qrcodes { + text-align: center; + margin-top: 20px; + } + + .tabs { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + margin-top: 20px; + + li { + margin: 0 20px; + color: $darkestgrey; + transition: all 0.25s; + + &:hover { + color: $black; + } + + &.active { + color: $black; + font-weight: bold; + } + } + } + } + section { margin: 25px 0; padding: 25px; - border-bottom: 1px solid $darkestgrey; h4 { font-size: 14px; font-weight: bold; - text-transform: uppercase; letter-spacing: 1.5px; margin-bottom: 10px; @@ -19,20 +63,33 @@ } } - .qrcode { - text-align: center; - margin-top: 20px; - } - p { + display: flex; + flex-direction: row; font-family: 'Roboto'; - text-align: center; font-size: 14px; font-weight: 200; - border-radius: 7px; background: $lightgrey; - border: 1px solid $main; - padding: 10px; + + span { + padding: 15px; + } + + span:nth-child(1) { + flex: 9; + overflow-x: scroll; + } + + span:nth-child(2) { + background: $darkgrey; + color: $black; + cursor: pointer; + transition: all 0.25s; + + &:hover { + background: $darkestgrey; + } + } } } } diff --git a/app/components/Wallet/Wallet.js b/app/components/Wallet/Wallet.js index 10130a5e..8c9b0216 100644 --- a/app/components/Wallet/Wallet.js +++ b/app/components/Wallet/Wallet.js @@ -13,7 +13,8 @@ class Wallet extends Component { super(props) this.state = { - modalOpen: false + modalOpen: false, + qrCodeType: 1 } } @@ -25,19 +26,29 @@ class Wallet extends Component { newAddress } = this.props - const { modalOpen } = this.state + const { modalOpen, qrCodeType } = this.state + + const changeQrCode = () => { + const qrCodeType = this.state.qrCodeType === 1 ? 2 : 1 + + this.setState({ qrCodeType }) + } return (
    { - (modalOpen && + ( + modalOpen && this.setState({ modalOpen: false })} pubkey={info.data.identity_pubkey} address={address} newAddress={newAddress} - />) + qrCodeType={qrCodeType} + changeQrCode={changeQrCode} + /> + ) }
    @@ -52,7 +63,7 @@ class Wallet extends Component {
    -
    this.setState({ modalOpen: true })}> +
    this.setState({ modalOpen: true })}> Address
    diff --git a/app/components/Wallet/Wallet.scss b/app/components/Wallet/Wallet.scss index 88b4e6bf..b2cf35e2 100644 --- a/app/components/Wallet/Wallet.scss +++ b/app/components/Wallet/Wallet.scss @@ -58,10 +58,10 @@ height: calc(100% - 50px); div { - font-size: 20px; - padding: 10px 25px; + padding: 7px 20px; background: $main; transition: background 0.25s; + color: $black; &:hover { background: darken($main, 10%); diff --git a/app/containers/Root.js b/app/containers/Root.js index e54a8840..da0e6794 100644 --- a/app/containers/Root.js +++ b/app/containers/Root.js @@ -3,9 +3,10 @@ import React from 'react' import { Provider, connect } from 'react-redux' import { ConnectedRouter } from 'react-router-redux' import PropTypes from 'prop-types' -import { fetchBlockHeight, lndSelectors } from 'reducers/lnd' -import LoadingBolt from 'components/LoadingBolt' -import LndSyncing from 'components/LndSyncing' + +import LoadingBolt from '../components/LoadingBolt' +import LndSyncing from '../components/LndSyncing' +import { fetchBlockHeight, lndSelectors } from '../reducers/lnd' import Routes from '../routes' const mapDispatchToProps = { @@ -18,11 +19,6 @@ const mapStateToProps = state => ({ syncPercentage: lndSelectors.syncPercentage(state) }) -type RootType = { - store: {}, - history: {} -}; - const Root = ({ store, history, @@ -40,7 +36,7 @@ const Root = ({ /> ) } - + // Don't launch the app without gRPC connection if (!lnd.grpcStarted) { return } diff --git a/app/index.js b/app/index.js index f7d279f0..c260f491 100644 --- a/app/index.js +++ b/app/index.js @@ -1,27 +1,27 @@ -import React from 'react'; -import { render } from 'react-dom'; -import { AppContainer } from 'react-hot-loader'; -import Root from './containers/Root'; -import { configureStore, history } from './store/configureStore'; -import './app.global.scss'; +import React from 'react' +import { render } from 'react-dom' +import { AppContainer } from 'react-hot-loader' +import Root from './containers/Root' +import { configureStore, history } from './store/configureStore' +import './app.global.scss' -const store = configureStore(); +const store = configureStore() render( , document.getElementById('root') -); +) if (module.hot) { module.hot.accept('./containers/Root', () => { - const NextRoot = require('./containers/Root'); // eslint-disable-line global-require + const NextRoot = require('./containers/Root') // eslint-disable-line global-require render( , document.getElementById('root') - ); - }); + ) + }) } diff --git a/app/lnd/config/index.js b/app/lnd/config/index.js index fb37f404..c0366490 100644 --- a/app/lnd/config/index.js +++ b/app/lnd/config/index.js @@ -8,7 +8,7 @@ import { join } from 'path' let loc switch (platform()) { case 'darwin': - loc = 'Library/Application\ Support/Lnd/tls.cert' + loc = 'Library/Application Support/Lnd/tls.cert' break case 'linux': loc = '.lnd/tls.cert' diff --git a/app/lnd/lib/lightning.js b/app/lnd/lib/lightning.js index a289e39d..f01c0ed1 100644 --- a/app/lnd/lib/lightning.js +++ b/app/lnd/lib/lightning.js @@ -6,7 +6,7 @@ import config from '../config' module.exports = (rpcpath, host) => { const lndCert = fs.readFileSync(config.cert) const credentials = grpc.credentials.createSsl(lndCert) - + const rpc = grpc.load(path.join(__dirname, 'rpc.proto')) return new rpc.lnrpc.Lightning(host, credentials) diff --git a/app/lnd/methods/paymentsController.js b/app/lnd/methods/paymentsController.js index 139486c7..6a5d5397 100644 --- a/app/lnd/methods/paymentsController.js +++ b/app/lnd/methods/paymentsController.js @@ -12,7 +12,7 @@ export function sendPaymentSync(lnd, { paymentRequest }) { return } - if (!data.payment_route) { reject({ error: data.payment_error }) } + if (!data || !data.payment_route) { reject({ error: data.payment_error }) } resolve(data) }) diff --git a/app/lnd/subscribe/transactions.js b/app/lnd/subscribe/transactions.js index 0c816c4a..5c3f0091 100644 --- a/app/lnd/subscribe/transactions.js +++ b/app/lnd/subscribe/transactions.js @@ -9,5 +9,5 @@ export default function subscribeToTransactions(mainWindow, lnd) { }) call.on('end', () => console.log('end')) call.on('error', error => console.log('error: ', error)) - call.on('status', status => console.log('status: ', status)) + call.on('status', status => console.log('TRANSACTION STATUS: ', status)) } diff --git a/app/lnd/utils/index.js b/app/lnd/utils/index.js new file mode 100644 index 00000000..6fa3f7c6 --- /dev/null +++ b/app/lnd/utils/index.js @@ -0,0 +1,42 @@ +import zbase32 from 'zbase32' + +function convertBigEndianBufferToLong(longBuffer) { + let longValue = 0 + const byteArray = Buffer.from(longBuffer).swap64() + + for (let i = byteArray.length - 1; i >= 0; i -= 1) { + longValue = (longValue * 256) + byteArray[i] + } + + return longValue +} + +export function decodeInvoice(payreq) { + const payreqBase32 = zbase32.decode(payreq) + + const bufferHexRotated = Buffer.from(payreqBase32).toString('hex') + const bufferHex = bufferHexRotated.substr(bufferHexRotated.length - 1, bufferHexRotated.length) + + bufferHexRotated.substr(0, bufferHexRotated.length - 1) + const buffer = Buffer.from(bufferHex, 'hex') + + const pubkeyBuffer = buffer.slice(0, 33) + const pubkey = pubkeyBuffer.toString('hex') + + const paymentHashBuffer = buffer.slice(33, 65) + const paymentHashHex = paymentHashBuffer.toString('hex') + + const valueBuffer = buffer.slice(65, 73) + + const amount = convertBigEndianBufferToLong(valueBuffer) + + return { + payreq, + pubkey, + amount, + r_hash: paymentHashHex + } +} + +export default { + decodeInvoice +} diff --git a/app/main.dev.js b/app/main.dev.js index 8f69f8e2..dfc91720 100644 --- a/app/main.dev.js +++ b/app/main.dev.js @@ -165,6 +165,7 @@ export const startLnd = () => { '--bitcoin.active', '--bitcoin.testnet', '--neutrino.active', + '--neutrino.connect=btcd0.lightning.computer:18333', '--neutrino.connect=faucet.lightning.community:18333', '--autopilot.active', '--debuglevel=debug', diff --git a/app/package.json b/app/package.json index dc68b51d..ba28606b 100644 --- a/app/package.json +++ b/app/package.json @@ -15,7 +15,7 @@ }, "license": "MIT", "dependencies": { - "grpc": "^1.6.6", + "grpc": "^1.7.3", "ps-node": "^0.1.6", "react-icons": "^2.2.5" } diff --git a/app/reducers/address.js b/app/reducers/address.js index 7ecb63f5..fb676836 100644 --- a/app/reducers/address.js +++ b/app/reducers/address.js @@ -5,7 +5,7 @@ import { ipcRenderer } from 'electron' export const GET_ADDRESS = 'GET_ADDRESS' export const RECEIVE_ADDRESS = 'RECEIVE_ADDRESS' -// LND expects types to be sent as int, so this object will allow mapping from string to int +// LND expects types to be sent as int, so this object will allow mapping from string to int const addressTypes = { p2wkh: 0, np2wkh: 1, diff --git a/app/reducers/channels.js b/app/reducers/channels.js index cc7f6c0d..e28f60d1 100644 --- a/app/reducers/channels.js +++ b/app/reducers/channels.js @@ -165,27 +165,32 @@ export const closeChannel = ({ channel_point }) => (dispatch) => { // TODO: Decide how to handle streamed updates for closing channels // Receive IPC event for closeChannel -export const closeChannelSuccessful = () => (dispatch) => { +export const closeChannelSuccessful = (event, data) => (dispatch) => { + console.log('PUSH CLOSE CHANNEL SUCCESSFUL: ', data) dispatch(fetchChannels()) } // Receive IPC event for updated closing channel -export const pushclosechannelupdated = () => (dispatch) => { +export const pushclosechannelupdated = (event, data) => (dispatch) => { + console.log('PUSH CLOSE CHANNEL UPDATED: ', data) dispatch(fetchChannels()) } // Receive IPC event for closing channel end -export const pushclosechannelend = () => (dispatch) => { +export const pushclosechannelend = (event, data) => (dispatch) => { + console.log('PUSH CLOSE CHANNEL END: ', data) dispatch(fetchChannels()) } // Receive IPC event for closing channel error -export const pushclosechannelerror = () => (dispatch) => { +export const pushclosechannelerror = (event, data) => (dispatch) => { + console.log('PUSH CLOSE CHANNEL END: ', data) dispatch(fetchChannels()) } // Receive IPC event for closing channel status -export const pushclosechannelstatus = () => (dispatch) => { +export const pushclosechannelstatus = (event, data) => (dispatch) => { + console.log('PUSH CLOSE CHANNEL STATUS: ', data) dispatch(fetchChannels()) } @@ -201,13 +206,13 @@ export const channelGraphData = (event, data) => (dispatch, getState) => { // dispatch(fetchDescribeNetwork()) // loop through the channel updates - for (let i = 0; i < channel_updates.length; i++) { + for (let i = 0; i < channel_updates.length; i += 1) { const channel_update = channel_updates[i] const { advertising_node, connecting_node } = channel_update // if our node is involved in this update we wanna show a notification if (info.data.identity_pubkey === advertising_node || info.data.identity_pubkey === connecting_node) { - // this channel has to do with the user, lets fetch a new channel list for them + // this channel has to do with the user, lets fetch a new channel list for them // TODO: full fetch is probably not necessary dispatch(fetchChannels()) diff --git a/app/reducers/info.js b/app/reducers/info.js index 0a80e8cc..f86641d3 100644 --- a/app/reducers/info.js +++ b/app/reducers/info.js @@ -1,7 +1,6 @@ import { createSelector } from 'reselect' import { ipcRenderer } from 'electron' -import { fetchBalance } from './balance' -import { newAddress } from './address' + // ------------------------------------ // Constants // ------------------------------------ @@ -25,8 +24,6 @@ export const fetchInfo = () => async (dispatch) => { // Receive IPC event for info export const receiveInfo = (event, data) => (dispatch) => { - dispatch(fetchBalance()) - dispatch(newAddress('p2pkh')) dispatch({ type: RECEIVE_INFO, data }) } diff --git a/app/reducers/lnd.js b/app/reducers/lnd.js index 997fec38..eaa19de3 100644 --- a/app/reducers/lnd.js +++ b/app/reducers/lnd.js @@ -59,7 +59,7 @@ export const lndStdout = (event, line) => (dispatch) => { trimmed = line.slice(line.indexOf('Catching up block hashes to height') + 'Catching up block hashes to height'.length).trim() height = trimmed.match(/[-]{0,1}[\d.]*[\d]+/g)[0] } - + dispatch({ type: RECEIVE_LINE, lndBlockHeight: height }) } @@ -95,7 +95,7 @@ const ACTION_HANDLERS = { [GET_BLOCK_HEIGHT]: state => ({ ...state, fetchingBlockHeight: true }), [RECEIVE_BLOCK_HEIGHT]: (state, { blockHeight }) => ({ ...state, blockHeight, fetchingBlockHeight: false }), - + [GRPC_DISCONNECTED]: state => ({ ...state, grpcStarted: false }), [GRPC_CONNECTED]: state => ({ ...state, grpcStarted: true }) } diff --git a/app/reducers/network.js b/app/reducers/network.js index 07680b57..0d0de227 100644 --- a/app/reducers/network.js +++ b/app/reducers/network.js @@ -172,9 +172,9 @@ const ACTION_HANDLERS = { [SET_CURRENT_ROUTE]: (state, { route }) => ({ ...state, currentRoute: route }), [SET_CURRENT_CHANNEL]: (state, { selectedChannel }) => ({ ...state, selectedChannel }), - + [SET_CURRENT_TAB]: (state, { currentTab }) => ({ ...state, currentTab }), - + [SET_CURRENT_PEER]: (state, { currentPeer }) => ({ ...state, currentPeer }), [UPDATE_PAY_REQ]: (state, { pay_req }) => ({ ...state, pay_req }), @@ -280,7 +280,7 @@ const initialState = { nodes: [], edges: [], selectedChannel: {}, - + currentTab: 1, currentPeer: {}, diff --git a/app/reducers/peers.js b/app/reducers/peers.js index 78084db4..7d88b705 100644 --- a/app/reducers/peers.js +++ b/app/reducers/peers.js @@ -124,7 +124,7 @@ const ACTION_HANDLERS = { [GET_PEERS]: state => ({ ...state, peersLoading: true }), [RECEIVE_PEERS]: (state, { peers }) => ({ ...state, peersLoading: false, peers }), - + [UPDATE_SEARCH_QUERY]: (state, { searchQuery }) => ({ ...state, searchQuery }) } diff --git a/app/routes/activity/components/components/Modal/Invoice/Invoice.js b/app/routes/activity/components/components/Modal/Invoice/Invoice.js index b82c464b..ddb78493 100644 --- a/app/routes/activity/components/components/Modal/Invoice/Invoice.js +++ b/app/routes/activity/components/components/Modal/Invoice/Invoice.js @@ -6,7 +6,7 @@ import 'moment-timezone' import QRCode from 'qrcode.react' -import { MdCheck } from 'react-icons/lib/md' +import { FaCircle } from 'react-icons/lib/fa' import CurrencyIcon from 'components/CurrencyIcon' import { btc } from 'utils' @@ -16,20 +16,33 @@ import styles from './Invoice.scss' const Invoice = ({ invoice, ticker, currentTicker }) => (
    -

    {invoice.memo}

    -

    - - - { - ticker.currency === 'usd' ? - btc.satoshisToUsd(invoice.value, currentTicker.price_usd) - : - btc.satoshisToBtc(invoice.value) - } - -

    +
    + { + !invoice.settled && +

    + + Not Paid +

    + } +
    +
    +

    {invoice.memo}

    +

    + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(invoice.value, currentTicker.price_usd) + : + btc.satoshisToBtc(invoice.value) + } + + BTC +

    +
    - + +
    +
    ( defaultValue={invoice.payment_request} />
    -
    - { - invoice.settled ? -

    Paid

    - : -

    Not Paid

    - } -

    Created on {invoice.creation_date * 1000} diff --git a/app/routes/activity/components/components/Modal/Invoice/Invoice.scss b/app/routes/activity/components/components/Modal/Invoice/Invoice.scss index 6a55e812..3880bfb0 100644 --- a/app/routes/activity/components/components/Modal/Invoice/Invoice.scss +++ b/app/routes/activity/components/components/Modal/Invoice/Invoice.scss @@ -1,72 +1,75 @@ @import '../../../../../../variables.scss'; .container { - padding: 40px; + .settled { + position: absolute; + top: 0; + padding: 10px 0 10px 40px; + color: $darkestgrey; + + svg { + line-height: 20px; + font-size: 10px; + vertical-align: middle; + } + + span { + font-size: 12px; + margin-left: 5px; + } + } + + header { + background: $lightgrey; + padding-bottom: 20px; + } h3 { - font-size: 24px; + font-size: 20px; color: $black; font-weight: bold; - text-align: center; - margin-bottom: 10px; + padding: 10px 40px; } h1 { - text-align: center; color: $main; - margin: 20px 20px 60px 0; + padding: 10px 40px; - svg { + .value { font-size: 30px; - vertical-align: top; } - span svg[data-icon='ltc'] { - width: 30px; - height: 30px; + i { + margin-left: 2px; vertical-align: top; - - g { - transform: scale(1.75) translate(-5px, -5px); - } - } - - .value { - font-size: 60px; } } .qrcode { text-align: center; + margin-top: 40px; + + } + + .input { + padding: 10px 40px; .paymentRequest { text-align: center; - font-size: 0.5vw; - margin-top: 20px; - padding: 5px; - border-radius: 5px; + font-size: 12px; + padding: 15px; background: $lightgrey; - border: 1px solid $darkgrey; + border: 1px solid transparent; display: block; - width: 100%; - } - } - - .settled { - text-align: center; - color: $main; - text-transform: uppercase; - font-size: 20px; - margin: 30px 0; - font-weight: bold; - - svg { - line-height: 20px; + width: 90%; + margin: 20px auto 0 auto; } } .date { text-align: center; + padding-bottom: 40px; + margin-top: 20px; time { margin-left: 3px; diff --git a/app/routes/activity/components/components/Modal/Modal.js b/app/routes/activity/components/components/Modal/Modal.js index 383316f5..b53a98df 100644 --- a/app/routes/activity/components/components/Modal/Modal.js +++ b/app/routes/activity/components/components/Modal/Modal.js @@ -6,6 +6,10 @@ import Transaction from './Transaction' import Payment from './Payment' import Invoice from './Invoice' +import { MdClose } from 'react-icons/lib/md' + +import styles from './Modal.scss' + const Modal = ({ modalType, modalProps, hideActivityModal, ticker, currentTicker }) => { const MODAL_COMPONENTS = { TRANSACTION: Transaction, @@ -23,7 +27,9 @@ const Modal = ({ modalType, modalProps, hideActivityModal, ticker, currentTicker right: '0', bottom: 'auto', width: '40%', - margin: '50px auto' + margin: '50px auto', + borderRadius: 'none', + padding: '0' } } @@ -41,6 +47,11 @@ const Modal = ({ modalType, modalProps, hideActivityModal, ticker, currentTicker parentSelector={() => document.body} style={customStyles} > +

    + hideActivityModal()}> + + +
    ) diff --git a/app/routes/activity/components/components/Modal/Modal.scss b/app/routes/activity/components/components/Modal/Modal.scss new file mode 100644 index 00000000..b8288b87 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Modal.scss @@ -0,0 +1,13 @@ +@import '../../../../../variables.scss'; + +.closeContainer { + background: $lightgrey; + text-align: right; + padding: 10px; + + span { + color: $darkestgrey; + font-size: 20px; + cursor: pointer; + } +} \ No newline at end of file diff --git a/app/routes/activity/components/components/Modal/Payment/Payment.js b/app/routes/activity/components/components/Modal/Payment/Payment.js index 6b27adf2..41f55619 100644 --- a/app/routes/activity/components/components/Modal/Payment/Payment.js +++ b/app/routes/activity/components/components/Modal/Payment/Payment.js @@ -12,21 +12,30 @@ import styles from './Payment.scss' const Payment = ({ payment, ticker, currentTicker }) => (
    -

    {payment.payment_hash}

    -

    - - - { - ticker.currency === 'usd' ? - btc.satoshisToUsd(payment.value, currentTicker.price_usd) - : - btc.satoshisToBtc(payment.value) - } - -

    +
    +
    +

    Sent

    +

    + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(payment.value, currentTicker.price_usd) + : + btc.satoshisToBtc(payment.value) + } + + + BTC + +

    +
    +

    {payment.payment_hash}

    +
    Fee
    {payment.fee}
    +
    Hops
    +
    {payment.path.length}
    Date
    {payment.creation_date * 1000} diff --git a/app/routes/activity/components/components/Modal/Payment/Payment.scss b/app/routes/activity/components/components/Modal/Payment/Payment.scss index 304fce58..6c88b58f 100644 --- a/app/routes/activity/components/components/Modal/Payment/Payment.scss +++ b/app/routes/activity/components/components/Modal/Payment/Payment.scss @@ -1,38 +1,44 @@ @import '../../../../../../variables.scss'; .container { - padding: 40px; + header { + padding: 5px 40px 20px 40px; + background: $lightgrey; + + .title { + display: flex; + flex-direction: row; + margin-bottom: 30px; + + h2 { + text-transform: uppercase; + font-size: 24px; + margin-right: 10px; + } + } + } h1 { - text-align: center; color: $main; - margin: 60px 30px 60px 0; - svg { - font-size: 30px; - vertical-align: top; + .value { + font-size: 24px; } - span svg[data-icon='ltc'] { - width: 30px; - height: 30px; + i { + margin-left: 2px; vertical-align: top; - - g { - transform: scale(1.75) translate(-5px, -5px); - } - } - - .value { - font-size: 80px; } } h3 { font-size: 14px; text-align: center; - color: $black; - font-weight: bold; + color: $darkestgrey; + } + + dl { + padding: 40px 40px 40px 40px; } dt { @@ -48,8 +54,8 @@ dd { text-align: right; font-weight: 400; - padding: 19px 0; + padding: 30px 0 10px 0; margin-left: 0; - border-top: 1px solid $darkgrey; + border-bottom: 1px solid $darkgrey; } } \ No newline at end of file diff --git a/app/routes/activity/components/components/Modal/Transaction/Transaction.js b/app/routes/activity/components/components/Modal/Transaction/Transaction.js index 80290714..f1359842 100644 --- a/app/routes/activity/components/components/Modal/Transaction/Transaction.js +++ b/app/routes/activity/components/components/Modal/Transaction/Transaction.js @@ -1,3 +1,4 @@ +import { shell } from 'electron' import React from 'react' import PropTypes from 'prop-types' @@ -12,31 +13,42 @@ import styles from './Transaction.scss' const Transaction = ({ transaction, ticker, currentTicker }) => (
    -

    - { - transaction.amount < 0 ? - 'Sent' - : - 'Received' - } -

    -

    {transaction.tx_hash}

    -

    - - - { - ticker.currency === 'usd' ? - btc.satoshisToUsd(transaction.amount, currentTicker.price_usd) - : - btc.satoshisToBtc(transaction.amount) - } - -

    +
    +
    +

    + { + transaction.amount < 0 ? + 'Sent' + : + 'Received' + } +

    +

    + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(transaction.amount, currentTicker.price_usd) + : + btc.satoshisToBtc(transaction.amount) + } + + BTC +

    +
    +

    shell.openExternal(`https://testnet.smartbit.com.au/tx/${transaction.tx_hash}`)}>{transaction.tx_hash}

    +
    Confirmations
    {transaction.num_confirmations}
    Fee
    -
    {transaction.total_fees}
    +
    + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(transaction.total_fees) + : + btc.satoshisToBtc(transaction.total_fees) + } +
    Date
    {transaction.time_stamp * 1000} diff --git a/app/routes/activity/components/components/Modal/Transaction/Transaction.scss b/app/routes/activity/components/components/Modal/Transaction/Transaction.scss index 283de75b..f7c3d0ba 100644 --- a/app/routes/activity/components/components/Modal/Transaction/Transaction.scss +++ b/app/routes/activity/components/components/Modal/Transaction/Transaction.scss @@ -1,48 +1,57 @@ @import '../../../../../../variables.scss'; .container { - padding: 40px; + header { + padding: 5px 40px 20px 40px; + background: $lightgrey; + + .title { + display: flex; + flex-direction: row; + + h2 { + text-transform: uppercase; + } + } + } h1 { text-align: center; color: $main; - margin: 60px 30px 60px 0; - svg { - font-size: 30px; - vertical-align: top; + .value { + font-size: 24px; } - span svg[data-icon='ltc'] { - width: 30px; - height: 30px; + i { + margin-left: 2px; vertical-align: top; - - g { - transform: scale(1.75) translate(-5px, -5px); - } - } - - .value { - font-size: 75px; } } h3 { font-size: 14px; text-align: center; - color: $black; - font-weight: bold; + color: $darkestgrey; + cursor: pointer; + + &:hover { + text-decoration: underline; + } } h2 { text-align: center; + margin-right: 10px; margin-bottom: 30px; text-transform: uppercase; - letter-spacing: 1.5px; font-size: 24px; } + dl { + padding: 40px 40px 40px 40px; + } + dt { text-align: left; float: left; @@ -56,8 +65,8 @@ dd { text-align: right; font-weight: 400; - padding: 19px 0; + padding: 30px 0 10px 0; margin-left: 0; - border-top: 1px solid $darkgrey; + border-bottom: 1px solid $darkgrey; } -} \ No newline at end of file +} diff --git a/app/routes/app/components/App.js b/app/routes/app/components/App.js index e11c1202..ce737c94 100644 --- a/app/routes/app/components/App.js +++ b/app/routes/app/components/App.js @@ -13,7 +13,7 @@ class App extends Component { fetchTicker() fetchInfo() - newAddress('p2pkh') + newAddress('np2wkh') } render() { diff --git a/app/routes/channels/components/Channels.js b/app/routes/channels/components/Channels.js index 4c68986d..8a086aac 100644 --- a/app/routes/channels/components/Channels.js +++ b/app/routes/channels/components/Channels.js @@ -22,7 +22,7 @@ class Channels extends Component { componentWillMount() { const { fetchChannels, fetchPeers } = this.props - + fetchChannels() fetchPeers() } @@ -64,7 +64,7 @@ class Channels extends Component { fetchChannels() // wait for the svg to appear as child - const svgTimeout = setTimeout(() => { + const svgTimeout = setTimeout(() => { if (icon[0].tagName === 'svg') { // spin icon for 1 sec icon[0].style.animation = 'spin 1000ms linear 1' @@ -73,7 +73,7 @@ class Channels extends Component { }, 1) // clear animation after the second so we can reuse it - const refreshTimeout = setTimeout(() => { + const refreshTimeout = setTimeout(() => { icon[0].style.animation = '' this.setState({ refreshing: false }) clearTimeout(refreshTimeout) @@ -96,7 +96,7 @@ class Channels extends Component {
    - +