From f1911c0fa4bf19ded1557bdecad6e588dd7e9b88 Mon Sep 17 00:00:00 2001 From: Jack Mallers Date: Thu, 4 Jan 2018 16:25:30 -0600 Subject: [PATCH] feature(contacts): loading state while adding a contact --- app/components/Contacts/ClosingContact.js | 2 +- app/components/Contacts/Contact.scss | 49 +++++++++++++++++++ app/components/Contacts/ContactsForm.js | 12 +++++ app/components/Contacts/ContactsForm.scss | 43 ++++++++++++++++ app/components/Contacts/LoadingContact.js | 28 +++++++++++ app/lnd/methods/channelController.js | 9 ++-- app/reducers/channels.js | 33 +++++++++++-- app/routes/contacts/components/Contacts.js | 14 +++++- .../contacts/containers/ContactsContainer.js | 1 + 9 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 app/components/Contacts/LoadingContact.js diff --git a/app/components/Contacts/ClosingContact.js b/app/components/Contacts/ClosingContact.js index 6d887f4d..fe03fd36 100644 --- a/app/components/Contacts/ClosingContact.js +++ b/app/components/Contacts/ClosingContact.js @@ -6,7 +6,7 @@ import { btc } from 'utils' import styles from './Contact.scss' const ClosingContact = ({ channel }) => ( -
  • +
  • diff --git a/app/components/Contacts/Contact.scss b/app/components/Contacts/Contact.scss index d8c71d01..749dac7e 100644 --- a/app/components/Contacts/Contact.scss +++ b/app/components/Contacts/Contact.scss @@ -7,6 +7,12 @@ padding: 30px 0; border-bottom: 1px solid $traditionalgrey; + &.loading { + .info { + opacity: 0.2; + } + } + .limits { display: flex; flex-direction: row; @@ -100,3 +106,46 @@ } } } + +@-webkit-keyframes animation-rotate { + 100% { + -webkit-transform: rotate(360deg); + } +} + +@-moz-keyframes animation-rotate { + 100% { + -moz-transform: rotate(360deg); + } +} + +@-o-keyframes animation-rotate { + 100% { + -o-transform: rotate(360deg); + } +} + +@keyframes animation-rotate { + 100% { + transform: rotate(360deg); + } +} + +.spinner { + border: 1px solid rgba(0, 0, 0, 0.1); + border-left-color: rgba(0, 0, 0, 0.4); + -webkit-border-radius: 999px; + -moz-border-radius: 999px; + border-radius: 999px; +} + +.spinner { + margin: 0 auto; + height: 50px; + width: 50px; + -webkit-animation: animation-rotate 1000ms linear infinite; + -moz-animation: animation-rotate 1000ms linear infinite; + -o-animation: animation-rotate 1000ms linear infinite; + animation: animation-rotate 1000ms linear infinite; +} + diff --git a/app/components/Contacts/ContactsForm.js b/app/components/Contacts/ContactsForm.js index 4e8cc34a..ec7bf54f 100644 --- a/app/components/Contacts/ContactsForm.js +++ b/app/components/Contacts/ContactsForm.js @@ -27,12 +27,24 @@ class ContactsForm extends React.Component { nonActiveChannelPubkeys, pendingOpenChannelPubkeys, filteredNetworkNodes, + loadingChannelPubkeys, showManualForm } = this.props const { editing, manualFormInput } = this.state + const renderRightSide = (node) => { + if (loadingChannelPubkeys.includes(node.pub_key)) { + return ( + +

    +
    +
    + + ) + } + if (activeChannelPubkeys.includes(node.pub_key)) { return ( diff --git a/app/components/Contacts/ContactsForm.scss b/app/components/Contacts/ContactsForm.scss index 0e094442..1860c1cf 100644 --- a/app/components/Contacts/ContactsForm.scss +++ b/app/components/Contacts/ContactsForm.scss @@ -188,3 +188,46 @@ } } } + +@-webkit-keyframes animation-rotate { + 100% { + -webkit-transform: rotate(360deg); + } +} + +@-moz-keyframes animation-rotate { + 100% { + -moz-transform: rotate(360deg); + } +} + +@-o-keyframes animation-rotate { + 100% { + -o-transform: rotate(360deg); + } +} + +@keyframes animation-rotate { + 100% { + transform: rotate(360deg); + } +} + +.spinner { + border: 1px solid rgba(0, 0, 0, 0.1); + border-left-color: rgba(0, 0, 0, 0.4); + -webkit-border-radius: 999px; + -moz-border-radius: 999px; + border-radius: 999px; +} + +.spinner { + margin: 0 auto; + height: 20px; + width: 20px; + -webkit-animation: animation-rotate 1000ms linear infinite; + -moz-animation: animation-rotate 1000ms linear infinite; + -o-animation: animation-rotate 1000ms linear infinite; + animation: animation-rotate 1000ms linear infinite; +} + diff --git a/app/components/Contacts/LoadingContact.js b/app/components/Contacts/LoadingContact.js new file mode 100644 index 00000000..2161c818 --- /dev/null +++ b/app/components/Contacts/LoadingContact.js @@ -0,0 +1,28 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { FaCircle } from 'react-icons/lib/fa' +import { btc } from 'utils' +import styles from './Contact.scss' + +const LoadingContact = ({ pubkey }) => ( +
  • +
    +

    + + Loading +

    +

    {pubkey}

    +
    +
    +
    +
    +
    +
    +
  • +) + +LoadingContact.propTypes = { + +} + +export default LoadingContact diff --git a/app/lnd/methods/channelController.js b/app/lnd/methods/channelController.js index 40a4fdaa..410b23d4 100644 --- a/app/lnd/methods/channelController.js +++ b/app/lnd/methods/channelController.js @@ -30,7 +30,11 @@ export function connectAndOpen(lnd, meta, event, payload) { const peer = find(peers, { pub_key: pubkey }) if (peer) { - console.log('we can open the channel') + console.log('already have the peer. can open the channel now') + const call = lnd.openChannel(channelPayload, meta) + + call.on('data', data => event.sender.send('pushchannelupdated', { pubkey, data })) + call.on('error', error => event.sender.send('pushchannelerror', { pubkey, error: error.toString() })) } else { console.log('connect to the peer first') connectPeer(lnd, meta, { pubkey, host }) @@ -41,9 +45,6 @@ export function connectAndOpen(lnd, meta, event, payload) { call.on('data', data => event.sender.send('pushchannelupdated', { data })) call.on('error', error => event.sender.send('pushchannelerror', { error: error.toString() })) - - call.on('end', () => event.sender.send('pushchannelend')) - call.on('status', status => event.sender.send('pushchannelstatus', { status })) }) .catch(err => { console.log('connectPeer err: ', err) diff --git a/app/reducers/channels.js b/app/reducers/channels.js index 0a752df8..0c692b6e 100644 --- a/app/reducers/channels.js +++ b/app/reducers/channels.js @@ -29,6 +29,9 @@ export const SET_VIEW_TYPE = 'SET_VIEW_TYPE' export const TOGGLE_CHANNEL_PULLDOWN = 'TOGGLE_CHANNEL_PULLDOWN' export const CHANGE_CHANNEL_FILTER = 'CHANGE_CHANNEL_FILTER' +export const ADD_LOADING_PUBKEY = 'ADD_LOADING_PUBKEY' +export const REMOVE_LOADING_PUBKEY = 'REMOVE_LOADING_PUBKEY' + // ------------------------------------ // Actions // ------------------------------------ @@ -91,6 +94,20 @@ export function setViewType(viewType) { } } +export function addLoadingPubkey(pubkey) { + return { + type: ADD_LOADING_PUBKEY, + pubkey + } +} + +export function removeLoadingPubkey(pubkey) { + return { + type: REMOVE_LOADING_PUBKEY, + pubkey + } +} + // Send IPC event for peers export const fetchChannels = () => async (dispatch) => { dispatch(getChannels()) @@ -105,6 +122,7 @@ export const openChannel = ({ pubkey, host, local_amt, push_amt }) => (dispatch) const localamt = btc.btcToSatoshis(local_amt) dispatch(openingChannel()) + dispatch(addLoadingPubkey(pubkey)) ipcRenderer.send('lnd', { msg: 'connectAndOpen', data: { pubkey, host, localamt } }) } @@ -118,9 +136,10 @@ export const channelSuccessful = () => (dispatch) => { } // Receive IPC event for updated channel -export const pushchannelupdated = (event, data) => (dispatch) => { +export const pushchannelupdated = (event, { pubkey, data }) => (dispatch) => { console.log('PUSH CHANNEL UPDATED: ', data) dispatch(fetchChannels()) + dispatch(removeLoadingPubkey(pubkey)) } // Receive IPC event for channel end @@ -130,10 +149,11 @@ export const pushchannelend = event => (dispatch) => { // eslint-disable-line } // Receive IPC event for channel error -export const pushchannelerror = (event, { error }) => (dispatch) => { +export const pushchannelerror = (event, { pubkey, error }) => (dispatch) => { console.log('PUSH CHANNEL ERROR: ', error) dispatch(openingFailure()) dispatch(setError(error)) + dispatch(removeLoadingPubkey(pubkey)) } // Receive IPC event for channel status @@ -269,7 +289,10 @@ const ACTION_HANDLERS = { [SET_VIEW_TYPE]: (state, { viewType }) => ({ ...state, viewType }), [TOGGLE_CHANNEL_PULLDOWN]: state => ({ ...state, filterPulldown: !state.filterPulldown }), - [CHANGE_CHANNEL_FILTER]: (state, { filter }) => ({ ...state, filterPulldown: false, filter }) + [CHANGE_CHANNEL_FILTER]: (state, { filter }) => ({ ...state, filterPulldown: false, filter }), + + [ADD_LOADING_PUBKEY]: (state, { pubkey }) => ({ ...state, loadingChannelPubkeys: [pubkey, ...state.loadingChannelPubkeys] }), + [REMOVE_LOADING_PUBKEY]: (state, { pubkey }) => ({ ...state, loadingChannelPubkeys: state.loadingChannelPubkeys.filter(loadingPubkey => loadingPubkey !== pubkey) }) } const channelsSelectors = {} @@ -427,7 +450,9 @@ const initialState = { { key: 'NON_ACTIVE_CHANNELS', name: 'Offline Contacts' }, { key: 'OPEN_PENDING_CHANNELS', name: 'Pending Contacts' }, { key: 'CLOSING_PENDING_CHANNELS', name: 'Closing Contacts' } - ] + ], + + loadingChannelPubkeys: [] } export default function channelsReducer(state = initialState, action) { diff --git a/app/routes/contacts/components/Contacts.js b/app/routes/contacts/components/Contacts.js index 43da439b..3dd00d35 100644 --- a/app/routes/contacts/components/Contacts.js +++ b/app/routes/contacts/components/Contacts.js @@ -12,6 +12,7 @@ import OnlineContact from 'components/Contacts/OnlineContact' import PendingContact from 'components/Contacts/PendingContact' import ClosingContact from 'components/Contacts/ClosingContact' import OfflineContact from 'components/Contacts/OfflineContact' +import LoadingContact from 'components/Contacts/LoadingContact' import plus from 'icons/plus.svg' @@ -40,7 +41,8 @@ class Contacts extends Component { searchQuery, filterPulldown, filter, - viewType + viewType, + loadingChannelPubkeys }, currentChannels, activeChannels, @@ -148,6 +150,16 @@ class Contacts extends Component {
      + { + loadingChannelPubkeys.map(pubkey => { + console.log('pubkey: ', pubkey) + + return ( + + ) + }) + } + { currentChannels.length > 0 && currentChannels.map((channel, index) => { if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) { diff --git a/app/routes/contacts/containers/ContactsContainer.js b/app/routes/contacts/containers/ContactsContainer.js index 568fa34c..e7a4bbf1 100644 --- a/app/routes/contacts/containers/ContactsContainer.js +++ b/app/routes/contacts/containers/ContactsContainer.js @@ -71,6 +71,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { contactsform: stateProps.contactsform, filteredNetworkNodes: stateProps.filteredNetworkNodes, + loadingChannelPubkeys: stateProps.channels.loadingChannelPubkeys, showManualForm: stateProps.showManualForm, activeChannelPubkeys: stateProps.activeChannelPubkeys,