Browse Source

feature(contacts): close contact and close contact loading UX

renovate/lint-staged-8.x
Jack Mallers 7 years ago
parent
commit
28d52af8e6
  1. 20
      app/components/Contacts/ContactModal.js
  2. 42
      app/components/Contacts/ContactModal.scss
  3. 11
      app/components/Contacts/LoadingContact.js
  4. 22
      app/lnd/methods/channelController.js
  5. 48
      app/reducers/channels.js
  6. 9
      app/routes/contacts/components/Contacts.js
  7. 6
      app/routes/contacts/containers/ContactsContainer.js

20
app/components/Contacts/ContactModal.js

@ -8,7 +8,14 @@ import { btc } from 'utils'
import styles from './ContactModal.scss'
const ContactModal = ({ isOpen, channel, closeContactModal, channelNodes }) => {
const ContactModal = ({
isOpen,
channel,
closeContactModal,
channelNodes,
closeChannel,
closingChannelIds
}) => {
if (!channel) { return <span /> }
const customStyles = {
@ -99,7 +106,16 @@ const ContactModal = ({ isOpen, channel, closeContactModal, channelNodes }) => {
</section>
<footer>
<div>Remove</div>
{
closingChannelIds.includes(channel.chan_id) ?
<span className={styles.inactive}>
<div className={styles.loading}>
<div className={styles.spinner} />
</div>
</span>
:
<div onClick={() => closeChannel({ channel_point: channel.channel_point, chan_id: channel.chan_id })}>Remove</div>
}
</footer>
</div>
}

42
app/components/Contacts/ContactModal.scss

@ -105,3 +105,45 @@
}
}
}
@-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;
}

11
app/components/Contacts/LoadingContact.js

@ -4,12 +4,19 @@ import { FaCircle } from 'react-icons/lib/fa'
import { btc } from 'utils'
import styles from './Contact.scss'
const LoadingContact = ({ pubkey }) => (
const LoadingContact = ({ pubkey, isClosing }) => (
<li className={`${styles.friend} ${styles.loading}`}>
<section className={styles.info}>
<p>
<FaCircle style={{ verticalAlign: 'top' }} />
<span>Loading</span>
<span>
{
isClosing ?
'Closing'
:
'Loading'
}
</span>
</p>
<h2>{pubkey}</h2>
</section>

22
app/lnd/methods/channelController.js

@ -123,20 +123,30 @@ export function listChannels(lnd, meta) {
* @return {[type]} [description]
*/
export function closeChannel(lnd, meta, event, payload) {
const chan_id = payload.chan_id
const tx = payload.channel_point.funding_txid.match(/.{2}/g).reverse().join('')
const res = {
channel_point: {
funding_txid: BufferUtil.hexToBuffer(tx),
output_index: Number(payload.channel_point.output_index)
},
force: true
force: false
}
return new Promise((resolve, reject) =>
pushclosechannel(lnd, meta, event, res)
.then(data => resolve(data))
.catch(error => reject(error))
)
return new Promise((resolve, reject) => {
try {
const call = lnd.closeChannel(res, meta)
call.on('data', data => event.sender.send('pushclosechannelupdated', { data, chan_id }))
call.on('end', () => event.sender.send('pushclosechannelend'))
call.on('error', error => event.sender.send('pushclosechannelerror', { error: error.toString(), chan_id }))
call.on('status', status => event.sender.send('pushclosechannelstatus', { status, chan_id }))
resolve(null, res)
} catch (error) {
reject(error, null)
}
})
}

48
app/reducers/channels.js

@ -33,6 +33,9 @@ export const CHANGE_CHANNEL_FILTER = 'CHANGE_CHANNEL_FILTER'
export const ADD_LOADING_PUBKEY = 'ADD_LOADING_PUBKEY'
export const REMOVE_LOADING_PUBKEY = 'REMOVE_LOADING_PUBKEY'
export const ADD_ClOSING_CHAN_ID = 'ADD_ClOSING_CHAN_ID'
export const REMOVE_ClOSING_CHAN_ID = 'REMOVE_ClOSING_CHAN_ID'
export const OPEN_CONTACT_MODAL = 'OPEN_CONTACT_MODAL'
export const CLOSE_CONTACT_MODAL = 'CLOSE_CONTACT_MODAL'
@ -112,6 +115,20 @@ export function removeLoadingPubkey(pubkey) {
}
}
export function addClosingChanId(chanId) {
return {
type: ADD_ClOSING_CHAN_ID,
chanId
}
}
export function removeClosingChanId(chanId) {
return {
type: REMOVE_ClOSING_CHAN_ID,
chanId
}
}
export function openContactModal(channel) {
return {
type: OPEN_CONTACT_MODAL,
@ -185,19 +202,24 @@ export const pushchannelstatus = (event, data) => (dispatch) => { // eslint-disa
}
// Send IPC event for opening a channel
export const closeChannel = ({ channel_point }) => (dispatch) => {
export const closeChannel = ({ channel_point, chan_id }) => (dispatch) => {
dispatch(closingChannel())
const channelPoint = channel_point.split(':')
dispatch(addClosingChanId(chan_id))
const [funding_txid, output_index] = channel_point.split(':')
console.log('funding_txid: ', funding_txid)
console.log('output_index: ', output_index)
console.log('chan_id: ', chan_id)
ipcRenderer.send(
'lnd',
{
msg: 'closeChannel',
data: {
channel_point: {
funding_txid: channelPoint[0],
output_index: channelPoint[1]
funding_txid,
output_index
},
force: true
chan_id
}
}
)
@ -211,9 +233,11 @@ export const closeChannelSuccessful = (event, data) => (dispatch) => {
}
// Receive IPC event for updated closing channel
export const pushclosechannelupdated = (event, data) => (dispatch) => {
export const pushclosechannelupdated = (event, { data, chan_id }) => (dispatch) => {
console.log('PUSH CLOSE CHANNEL UPDATED: ', data)
console.log('PUSH CLOSE CHANNEL chan_id: ', chan_id)
dispatch(fetchChannels())
dispatch(removeClosingChanId(chan_id))
}
// Receive IPC event for closing channel end
@ -223,9 +247,11 @@ export const pushclosechannelend = (event, data) => (dispatch) => {
}
// Receive IPC event for closing channel error
export const pushclosechannelerror = (event, data) => (dispatch) => {
console.log('PUSH CLOSE CHANNEL END: ', data)
dispatch(fetchChannels())
export const pushclosechannelerror = (event, { error, chan_id }) => (dispatch) => {
console.log('PUSH CLOSE CHANNEL END: ', error)
console.log('PUSH CLOSE CHANNEL chan_id: ', chan_id)
dispatch(setError(error))
dispatch(removeClosingChanId(chan_id))
}
// Receive IPC event for closing channel status
@ -315,6 +341,9 @@ const ACTION_HANDLERS = {
[ADD_LOADING_PUBKEY]: (state, { pubkey }) => ({ ...state, loadingChannelPubkeys: [pubkey, ...state.loadingChannelPubkeys] }),
[REMOVE_LOADING_PUBKEY]: (state, { pubkey }) => ({ ...state, loadingChannelPubkeys: state.loadingChannelPubkeys.filter(loadingPubkey => loadingPubkey !== pubkey) }),
[ADD_ClOSING_CHAN_ID]: (state, { chanId }) => ({ ...state, closingChannelIds: [chanId, ...state.closingChannelIds] }),
[REMOVE_ClOSING_CHAN_ID]: (state, { chanId }) => ({ ...state, closingChannelIds: state.closingChannelIds.filter(closingChanId => closingChanId !== chanId) }),
[OPEN_CONTACT_MODAL]: (state, { channel }) => ({ ...state, contactModal: { isOpen: true, channel } }),
[CLOSE_CONTACT_MODAL]: state => ({ ...state, contactModal: { isOpen: false, channel: null } })
@ -489,6 +518,7 @@ const initialState = {
],
loadingChannelPubkeys: [],
closingChannelIds: [],
contactModal: {
isOpen: false,

9
app/routes/contacts/components/Contacts.js

@ -43,7 +43,8 @@ class Contacts extends Component {
filterPulldown,
filter,
viewType,
loadingChannelPubkeys
loadingChannelPubkeys,
closingChannelIds
},
currentChannels,
activeChannels,
@ -156,12 +157,14 @@ class Contacts extends Component {
<ul className={`${styles.friends} ${filterPulldown && styles.fade}`}>
{
loadingChannelPubkeys.map(pubkey => <LoadingContact pubkey={pubkey} />)
loadingChannelPubkeys.map(pubkey => <LoadingContact pubkey={pubkey} isClosing={false} />)
}
{
currentChannels.length > 0 && currentChannels.map((channel, index) => {
if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) {
if (closingChannelIds.includes(channel.chan_id)) {
return <LoadingContact pubkey={channel.remote_pubkey} isClosing={true} />
} else if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) {
return <PendingContact channel={channel} key={index} />
} else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) {
return <ClosingContact channel={channel} key={index} />

6
app/routes/contacts/containers/ContactsContainer.js

@ -4,6 +4,7 @@ import { connect } from 'react-redux'
import {
fetchChannels,
openChannel,
closeChannel,
updateChannelSearchQuery,
toggleFilterPulldown,
@ -37,6 +38,7 @@ const mapDispatchToProps = {
updateContactFormSearchQuery,
updateContactCapacity,
openChannel,
closeChannel,
updateChannelSearchQuery,
toggleFilterPulldown,
changeFilter,
@ -70,10 +72,12 @@ const mapStateToProps = state => ({
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const contactModalProps = {
closeContactModal: dispatchProps.closeContactModal,
closeChannel: dispatchProps.closeChannel,
isOpen: stateProps.channels.contactModal.isOpen,
channel: stateProps.channels.contactModal.channel,
channelNodes: stateProps.channelNodes
channelNodes: stateProps.channelNodes,
closingChannelIds: stateProps.channels.closingChannelIds
}
const contactsFormProps = {

Loading…
Cancel
Save