diff --git a/app/components/Contacts/ContactModal.js b/app/components/Contacts/ContactModal.js
index 58a760ab..77f41fc3 100644
--- a/app/components/Contacts/ContactModal.js
+++ b/app/components/Contacts/ContactModal.js
@@ -26,7 +26,7 @@ const ContactModal = ({
},
content: {
top: 'auto',
- left: '20%',
+ left: '0',
right: '0',
bottom: 'auto',
width: '40%',
diff --git a/app/components/Contacts/ContactsForm.scss b/app/components/Contacts/ContactsForm.scss
index 19123176..977195f9 100644
--- a/app/components/Contacts/ContactsForm.scss
+++ b/app/components/Contacts/ContactsForm.scss
@@ -6,7 +6,7 @@
margin: 50px auto;
position: absolute;
top: auto;
- left: 20%;
+ left: 0;
right: 0;
bottom: auto;
background: $white;
diff --git a/app/components/Contacts/Network.js b/app/components/Contacts/Network.js
index fd0b6c99..58ced5e1 100644
--- a/app/components/Contacts/Network.js
+++ b/app/components/Contacts/Network.js
@@ -1,56 +1,165 @@
-import React from 'react'
+import React, { Component } from 'react'
import PropTypes from 'prop-types'
+import find from 'lodash/find'
import Isvg from 'react-inlinesvg'
-import { FaAngleDown, FaCircle } from 'react-icons/lib/fa'
+import { FaAngleDown, FaCircle, FaRepeat } from 'react-icons/lib/fa'
import { btc } from 'utils'
import plus from 'icons/plus.svg'
import search from 'icons/search.svg'
import styles from './Network.scss'
-const Network = ({ channels, balance, currentTicker }) => {
- console.log('channels: ', channels)
-
- return (
-
-
-
- My Network
-
- {btc.satoshisToBtc(balance.channelBalance)}BTC ≈ ${btc.satoshisToUsd(balance.channelBalance, currentTicker.price_usd).toLocaleString()}
-
-
-
-
-
-
-
-
- All
-
-
- Refresh
-
+class Network extends Component {
+ constructor(props) {
+ super(props)
+
+ this.state = {
+ refreshing: false
+ }
+ }
+
+ render() {
+ const {
+ channels: {
+ searchQuery,
+ filterPulldown,
+ filter,
+ loadingChannelPubkeys,
+ closingChannelIds
+ },
+ currentChannels,
+ balance,
+ currentTicker,
+
+ nodes,
+
+ fetchChannels,
+ openContactsForm,
+
+ nonActiveFilters,
+ toggleFilterPulldown,
+ changeFilter,
+
+ updateChannelSearchQuery
+ } = this.props
+
+
+ const refreshClicked = () => {
+ // turn the spinner on
+ this.setState({ refreshing: true })
+
+ // store event in icon so we dont get an error when react clears it
+ const icon = this.repeat.childNodes
+
+ // fetch channels
+ fetchChannels()
+
+ // wait for the svg to appear as child
+ const svgTimeout = setTimeout(() => {
+ if (icon[0].tagName === 'svg') {
+ // spin icon for 1 sec
+ icon[0].style.animation = 'spin 1000ms linear 1'
+ clearTimeout(svgTimeout)
+ }
+ }, 1)
+
+ // clear animation after the second so we can reuse it
+ const refreshTimeout = setTimeout(() => {
+ icon[0].style.animation = ''
+ this.setState({ refreshing: false })
+ clearTimeout(refreshTimeout)
+ }, 1000)
+ }
+
+ const displayNodeName = (channel) => {
+ const node = find(nodes, node => channel.remote_pubkey === node.pub_key)
+
+ if (node && node.alias.length) { return node.alias }
+
+ return channel.remote_pubkey ? channel.remote_pubkey.substring(0, 10) : channel.remote_node_pub.substring(0, 10)
+ }
+
+ const channelStatus = (channel) => {
+ if (Object.prototype.hasOwnProperty.call(channel, 'confirmation_height')) { return 'pending' }
+ if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) { return 'closing' }
+ if (!channel.active) { return 'offline' }
+
+ return 'online'
+ }
+
+ return (
+
+
+
+ My Network
+
+ {btc.satoshisToBtc(balance.channelBalance)}BTC ≈ ${btc.satoshisToUsd(balance.channelBalance, currentTicker.price_usd).toLocaleString()}
+
+
+
-
- {
- channels.channels.map(channel => {
- console.log('channel: ', channel)
- })
- }
-
-
+
+
+
+
+ {filter.name}
+
+
+ {
+ nonActiveFilters.map(f => (
+ - changeFilter(f)}>
+ {f.name}
+
+ ))
+ }
+
+
+
+
+ { this.repeat = ref }}>
+ {
+ this.state.refreshing ?
+
+ :
+ 'Refresh'
+ }
+
+
+
-
-
- )
+
+ {
+ currentChannels.length > 0 && currentChannels.map((channelObj, index) => {
+ const channel = Object.prototype.hasOwnProperty.call(channelObj, 'channel') ? channelObj.channel : channelObj
+ return (
+ -
+ {displayNodeName(channel)}
+
+
+ )
+ })
+ }
+
+
+
+
+
+ )
+ }
}
Network.propTypes = {}
diff --git a/app/components/Contacts/Network.scss b/app/components/Contacts/Network.scss
index 4b0c071d..39598abb 100644
--- a/app/components/Contacts/Network.scss
+++ b/app/components/Contacts/Network.scss
@@ -21,30 +21,78 @@
font-size: 14px;
font-weight: bold;
letter-spacing: 1.2px;
+ margin-bottom: 5px;
}
.channelAmount {
font-size: 10px;
opacity: 0.5;
}
+
+ .addChannel {
+ cursor: pointer;
+ transition: all 0.25s;
+
+ &:hover {
+ color: $darkestgrey;
+ }
+ }
}
.channels {
padding: 20px;
.listHeader {
+ position: relative;
display: flex;
flex-direction: row;
justify-content: space-between;
+ align-items: baseline;
+
+ h2, h2 span {
+ color: $white;
+ cursor: pointer;
+ transition: color 0.25s;
+
+ &:hover {
+ color: $darkestgrey;
+ }
+ }
+
+ h2, .filters li {
+ font-size: 12px;
+ }
+
+ .filters {
+ display: none;
+
+ &.active {
+ display: block;
+ position: absolute;
+ bottom: -80px;
+ z-index: 10;
+
+ li {
+ margin: 5px 0;
+ cursor: pointer;
+ color: $white;
+
+ &:hover {
+ color: $darkestgrey;
+ }
+ }
+ }
+ }
span {
- color: white;
- opacity: 0.5;
+ color: $white;
+ opacity: 1;
font-size: 10px;
cursor: pointer;
-
- &:nth-child(1) {
- opacity: 1;
+ transition: all 0.25s;
+
+ &:hover {
+ opacity: 0.5;
}
}
}
@@ -53,6 +101,10 @@
margin-top: 20px;
}
+ .fade {
+ opacity: 0.15;
+ }
+
.channel {
display: flex;
flex-direction: row;
diff --git a/app/components/Wallet/ReceiveModal.js b/app/components/Wallet/ReceiveModal.js
index 02498160..8a02f0db 100644
--- a/app/components/Wallet/ReceiveModal.js
+++ b/app/components/Wallet/ReceiveModal.js
@@ -17,7 +17,7 @@ const ReceiveModal = ({
},
content: {
top: 'auto',
- left: '20%',
+ left: '0',
right: '0',
bottom: 'auto',
width: '40%',
diff --git a/app/reducers/channels.js b/app/reducers/channels.js
index f38c4ae3..6c255519 100644
--- a/app/reducers/channels.js
+++ b/app/reducers/channels.js
@@ -512,13 +512,13 @@ const initialState = {
viewType: 0,
filterPulldown: false,
- filter: { key: 'ALL_CHANNELS', name: 'All Contacts' },
+ filter: { key: 'ALL_CHANNELS', name: 'All' },
filters: [
- { key: 'ALL_CHANNELS', name: 'All Contacts' },
- { key: 'ACTIVE_CHANNELS', name: 'Online Contacts' },
- { key: 'NON_ACTIVE_CHANNELS', name: 'Offline Contacts' },
- { key: 'OPEN_PENDING_CHANNELS', name: 'Pending Contacts' },
- { key: 'CLOSING_PENDING_CHANNELS', name: 'Closing Contacts' }
+ { key: 'ALL_CHANNELS', name: 'All' },
+ { key: 'ACTIVE_CHANNELS', name: 'Online' },
+ { key: 'NON_ACTIVE_CHANNELS', name: 'Offline' },
+ { key: 'OPEN_PENDING_CHANNELS', name: 'Pending' },
+ { key: 'CLOSING_PENDING_CHANNELS', name: 'Closing' }
],
loadingChannelPubkeys: [],
diff --git a/app/routes/activity/components/components/Activity.scss b/app/routes/activity/components/components/Activity.scss
index 07cc2b56..2eca71a2 100644
--- a/app/routes/activity/components/components/Activity.scss
+++ b/app/routes/activity/components/components/Activity.scss
@@ -80,12 +80,12 @@
position: relative;
width: 20px;
height: 20px;
- background: $main;
+ background: #31343f;
border-radius: 50%;
margin-right: 5px;
svg {
- color: $spaceblue;
+ color: $white;
font-size: 10px;
vertical-align: middle;
display: flex;
diff --git a/app/routes/activity/components/components/Modal/Modal.js b/app/routes/activity/components/components/Modal/Modal.js
index 4e040aef..349dde3a 100644
--- a/app/routes/activity/components/components/Modal/Modal.js
+++ b/app/routes/activity/components/components/Modal/Modal.js
@@ -24,7 +24,7 @@ const Modal = ({
},
content: {
top: 'auto',
- left: '20%',
+ left: '0',
right: '0',
bottom: 'auto',
width: '40%',
diff --git a/app/routes/app/components/App.js b/app/routes/app/components/App.js
index 791ea8ba..79cbb9e4 100644
--- a/app/routes/app/components/App.js
+++ b/app/routes/app/components/App.js
@@ -5,17 +5,19 @@ import LoadingBolt from 'components/LoadingBolt'
import Form from 'components/Form'
import ModalRoot from 'components/ModalRoot'
import Network from 'components/Contacts/Network'
+import ContactsForm from 'components/Contacts/ContactsForm'
import styles from './App.scss'
class App extends Component {
componentWillMount() {
- const { fetchTicker, fetchInfo, newAddress, fetchChannels, fetchBalance } = this.props
+ const { fetchTicker, fetchInfo, newAddress, fetchChannels, fetchBalance, fetchDescribeNetwork } = this.props
fetchTicker()
fetchInfo()
newAddress('np2wkh')
fetchChannels()
fetchBalance()
+ fetchDescribeNetwork()
}
render() {
@@ -35,6 +37,10 @@ class App extends Component {
error: { error },
clearError,
+ contactsFormProps,
+
+ networkTabProps,
+
children
} = this.props
@@ -52,16 +58,15 @@ class App extends Component {
currency={ticker.currency}
/>
+
+
{children}
-
+
+
)
}
diff --git a/app/routes/app/containers/AppContainer.js b/app/routes/app/containers/AppContainer.js
index 148c191e..e5180c5a 100644
--- a/app/routes/app/containers/AppContainer.js
+++ b/app/routes/app/containers/AppContainer.js
@@ -17,9 +17,32 @@ import { createInvoice, fetchInvoice } from 'reducers/invoice'
import { fetchBlockHeight, lndSelectors } from 'reducers/lnd'
-import { fetchChannels } from 'reducers/channels'
+import {
+ fetchChannels,
+ openChannel,
+ channelsSelectors,
+ currentChannels,
+
+ toggleFilterPulldown,
+ changeFilter,
+
+ updateChannelSearchQuery
+} from 'reducers/channels'
+
+import {
+ openContactsForm,
+ closeContactsForm,
+ updateContactFormSearchQuery,
+ updateManualFormSearchQuery,
+ updateContactCapacity,
+ contactFormSelectors,
+ updateManualFormErrors
+} from 'reducers/contactsform'
+
import { fetchBalance } from 'reducers/balance'
+import { fetchDescribeNetwork } from 'reducers/network'
+
import { clearError } from 'reducers/error'
@@ -53,8 +76,23 @@ const mapDispatchToProps = {
fetchBlockHeight,
clearError,
+ fetchBalance,
+
fetchChannels,
- fetchBalance
+ openChannel,
+ toggleFilterPulldown,
+ changeFilter,
+ updateChannelSearchQuery,
+
+ openContactsForm,
+ closeContactsForm,
+ updateContactFormSearchQuery,
+ updateManualFormSearchQuery,
+ updateContactCapacity,
+ contactFormSelectors,
+ updateManualFormErrors,
+
+ fetchDescribeNetwork
}
const mapStateToProps = state => ({
@@ -65,7 +103,9 @@ const mapStateToProps = state => ({
info: state.info,
payment: state.payment,
transaction: state.transaction,
+ peers: state.peers,
channels: state.channels,
+ contactsform: state.contactsform,
balance: state.balance,
form: state.form,
@@ -77,6 +117,8 @@ const mapStateToProps = state => ({
error: state.error,
+ network: state.network,
+
currentTicker: tickerSelectors.currentTicker(state),
isOnchain: payFormSelectors.isOnchain(state),
isLn: payFormSelectors.isLn(state),
@@ -84,7 +126,17 @@ const mapStateToProps = state => ({
inputCaption: payFormSelectors.inputCaption(state),
showPayLoadingScreen: payFormSelectors.showPayLoadingScreen(state),
payFormIsValid: payFormSelectors.payFormIsValid(state),
- syncPercentage: lndSelectors.syncPercentage(state)
+ syncPercentage: lndSelectors.syncPercentage(state),
+
+ filteredNetworkNodes: contactFormSelectors.filteredNetworkNodes(state),
+ showManualForm: contactFormSelectors.showManualForm(state),
+ manualFormIsValid: contactFormSelectors.manualFormIsValid(state),
+
+ currentChannels: currentChannels(state),
+ activeChannelPubkeys: channelsSelectors.activeChannelPubkeys(state),
+ nonActiveChannelPubkeys: channelsSelectors.nonActiveChannelPubkeys(state),
+ pendingOpenChannelPubkeys: channelsSelectors.pendingOpenChannelPubkeys(state),
+ nonActiveFilters: channelsSelectors.nonActiveFilters(state)
})
const mergeProps = (stateProps, dispatchProps, ownProps) => {
@@ -180,16 +232,57 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
return {}
}
+ const networkTabProps = {
+ currentChannels: stateProps.currentChannels,
+ channels: stateProps.channels,
+ balance: stateProps.balance,
+ currentTicker: stateProps.currentTicker,
+ contactsform: stateProps.contactsform,
+ nodes: stateProps.network.nodes,
+ nonActiveFilters: stateProps.nonActiveFilters,
+
+ fetchChannels: dispatchProps.fetchChannels,
+ openContactsForm: dispatchProps.openContactsForm,
+ contactFormSelectors: dispatchProps.contactFormSelectors,
+ updateManualFormError: dispatchProps.updateManualFormErrors,
+ toggleFilterPulldown: dispatchProps.toggleFilterPulldown,
+ changeFilter: dispatchProps.changeFilter,
+ updateChannelSearchQuery: dispatchProps.updateChannelSearchQuery
+ }
+
+ const contactsFormProps = {
+ closeContactsForm: dispatchProps.closeContactsForm,
+ updateContactFormSearchQuery: dispatchProps.updateContactFormSearchQuery,
+ updateManualFormSearchQuery: dispatchProps.updateManualFormSearchQuery,
+ updateContactCapacity: dispatchProps.updateContactCapacity,
+ openChannel: dispatchProps.openChannel,
+ updateManualFormErrors: dispatchProps.updateManualFormErrors,
+
+ contactsform: stateProps.contactsform,
+ filteredNetworkNodes: stateProps.filteredNetworkNodes,
+ loadingChannelPubkeys: stateProps.channels.loadingChannelPubkeys,
+ showManualForm: stateProps.showManualForm,
+ manualFormIsValid: stateProps.manualFormIsValid,
+ activeChannelPubkeys: stateProps.activeChannelPubkeys,
+ nonActiveChannelPubkeys: stateProps.nonActiveChannelPubkeys,
+ pendingOpenChannelPubkeys: stateProps.pendingOpenChannelPubkeys
+ }
+
return {
...stateProps,
...dispatchProps,
...ownProps,
+ // props for the network sidebar
+ networkTabProps,
+ // props for the contacts form
+ contactsFormProps,
// Props to pass to the pay form
formProps: formProps(stateProps.form.formType),
// action to close form
closeForm: () => dispatchProps.setFormType(null)
+
}
}