diff --git a/app/components/Wallet/Wallet.js b/app/components/Wallet/Wallet.js index 75f28121..c565683c 100644 --- a/app/components/Wallet/Wallet.js +++ b/app/components/Wallet/Wallet.js @@ -30,7 +30,8 @@ const Wallet = ({ setCurrency, setWalletCurrencyFilters, network, - settingsProps + settingsProps, + paymentTimeout }) => { const fiatAmount = btc.satoshisToFiat( parseInt(balance.walletBalance, 10) + parseInt(balance.channelBalance, 10), @@ -112,8 +113,11 @@ const Wallet = ({
{showPayLoadingScreen && ( -
-
Sending your transaction...
+
+
+ {paymentTimeout / 1000} +
+
Sending your transaction
)} {showSuccessPayScreen && ( @@ -165,6 +169,7 @@ Wallet.propTypes = { settingsProps: PropTypes.object.isRequired, currentCurrencyFilters: PropTypes.array.isRequired, currencyName: PropTypes.string.isRequired, + paymentTimeout: PropTypes.number.isRequired, setCurrency: PropTypes.func.isRequired, setWalletCurrencyFilters: PropTypes.func.isRequired } diff --git a/app/components/Wallet/Wallet.scss b/app/components/Wallet/Wallet.scss index 5444818a..8cb8ce1d 100644 --- a/app/components/Wallet/Wallet.scss +++ b/app/components/Wallet/Wallet.scss @@ -196,9 +196,14 @@ transition: all 0.25s; } + .spinnerContainer { + position: relative; + display: inline; + } + .spinner { - height: 20px; - width: 20px; + height: 30px; + width: 30px; border: 1px solid rgba(235, 184, 100, 0.1); border-left-color: rgba(235, 184, 100, 0.4); -webkit-border-radius: 999px; @@ -210,6 +215,15 @@ animation: animation-rotate 1000ms linear infinite; } + .timeout { + position: absolute; + top: 20%; + left: 0; + font-size: 10px; + width: 32px; + text-align: center; + } + .icon { margin-right: 5px; } diff --git a/app/reducers/payment.js b/app/reducers/payment.js index c07e07ad..25dc379a 100644 --- a/app/reducers/payment.js +++ b/app/reducers/payment.js @@ -15,6 +15,10 @@ export const RECEIVE_PAYMENTS = 'RECEIVE_PAYMENTS' export const SEND_PAYMENT = 'SEND_PAYMENT' +export const TICK_TIMEOUT = 'TICK_TIMEOUT' +export const SET_INTERVAL = 'SET_INTERVAL' +export const RESET_TIMEOUT = 'RESET_TIMEOUT' + export const PAYMENT_SUCCESSFULL = 'PAYMENT_SUCCESSFULL' export const PAYMENT_FAILED = 'PAYMENT_FAILED' @@ -43,6 +47,25 @@ export function sendPayment() { } } +export function tickTimeout() { + return { + type: TICK_TIMEOUT + } +} + +export function setPaymentInterval(paymentInterval) { + return { + type: SET_INTERVAL, + paymentInterval + } +} + +export function resetTimeout() { + return { + type: RESET_TIMEOUT + } +} + export function paymentSuccessfull(payment) { return { type: PAYMENT_SUCCESSFULL, @@ -96,21 +119,30 @@ export const paymentFailed = (event, { error }) => dispatch => { dispatch(setError(error)) } -export const payInvoice = paymentRequest => dispatch => { +export const payInvoice = paymentRequest => (dispatch, getState) => { dispatch(sendPayment()) ipcRenderer.send('lnd', { msg: 'sendPayment', data: { paymentRequest } }) + // Set an interval to call tick which will continuously tick down the ticker until the payment goes through or it hits + // 0 and throws an error. We also call setPaymentInterval so we are storing the interval. This allows us to clear the + // interval in flexible ways whenever we need to + const paymentInterval = setInterval(() => tick(dispatch, getState), 1000) + dispatch(setPaymentInterval(paymentInterval)) + // Close the form modal once the payment has been sent dispatch(setFormType(null)) +} - // if LND hangs on sending the payment we'll cut it after 10 seconds and return an error - // setTimeout(() => { - // const { payment } = getState() +// Tick checks if the payment is sending and checks the timeout every second. If the payment is still sending and the +// timeout is above 0 it will continue to tick it down, once we hit 0 we fire an error to the user and reset the reducer +const tick = (dispatch, getState) => { + const { payment } = getState() - // if (payment.sendingPayment) { - // dispatch(paymentFailed(null, { error: 'Shoot, we\'re having some trouble sending your payment.' })) - // } - // }, 10000) + if (payment.sendingPayment && payment.paymentTimeout <= 0) { + dispatch(paymentFailed(null, { error: 'Shoot, there was some trouble sending your payment.' })) + } else { + dispatch(tickTimeout()) + } } // ------------------------------------ @@ -121,9 +153,32 @@ const ACTION_HANDLERS = { [RECEIVE_PAYMENTS]: (state, { payments }) => ({ ...state, paymentLoading: false, payments }), [SET_PAYMENT]: (state, { payment }) => ({ ...state, payment }), + [SEND_PAYMENT]: state => ({ ...state, sendingPayment: true }), - [PAYMENT_SUCCESSFULL]: state => ({ ...state, sendingPayment: false }), - [PAYMENT_FAILED]: state => ({ ...state, sendingPayment: false }), + + [TICK_TIMEOUT]: state => ({ ...state, paymentTimeout: state.paymentTimeout - 1000 }), + [SET_INTERVAL]: (state, { paymentInterval }) => ({ ...state, paymentInterval }), + + [PAYMENT_SUCCESSFULL]: state => { + clearInterval(state.paymentInterval) + + return { + ...state, + sendingPayment: false, + paymentInterval: null, + paymentTimeout: 60000 + } + }, + [PAYMENT_FAILED]: state => { + clearInterval(state.paymentInterval) + + return { + ...state, + sendingPayment: false, + paymentInterval: null, + paymentTimeout: 60000 + } + }, [SHOW_SUCCESS_SCREEN]: state => ({ ...state, showSuccessPayScreen: true }), [HIDE_SUCCESS_SCREEN]: state => ({ ...state, showSuccessPayScreen: false }) @@ -142,6 +197,8 @@ export { paymentSelectors } const initialState = { sendingPayment: false, paymentLoading: false, + paymentTimeout: 60000, + paymentInterval: null, payments: [], payment: null, showSuccessPayScreen: false diff --git a/app/routes/activity/containers/ActivityContainer.js b/app/routes/activity/containers/ActivityContainer.js index 8f188f01..e1a084db 100644 --- a/app/routes/activity/containers/ActivityContainer.js +++ b/app/routes/activity/containers/ActivityContainer.js @@ -98,6 +98,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => ({ currentCurrencyFilters: stateProps.currentCurrencyFilters, currencyName: stateProps.currencyName, network: stateProps.info.network, + paymentTimeout: stateProps.payment.paymentTimeout, setCurrency: dispatchProps.setCurrency, setWalletCurrencyFilters: dispatchProps.setWalletCurrencyFilters, diff --git a/test/unit/reducers/__snapshots__/payment.spec.js.snap b/test/unit/reducers/__snapshots__/payment.spec.js.snap index e756e959..ee86c143 100644 --- a/test/unit/reducers/__snapshots__/payment.spec.js.snap +++ b/test/unit/reducers/__snapshots__/payment.spec.js.snap @@ -3,7 +3,9 @@ exports[`reducers paymentReducer should correctly getPayments 1`] = ` Object { "payment": null, + "paymentInterval": null, "paymentLoading": true, + "paymentTimeout": 60000, "payments": Array [], "sendingPayment": false, "showSuccessPayScreen": false, @@ -13,7 +15,9 @@ Object { exports[`reducers paymentReducer should correctly paymentSuccessful 1`] = ` Object { "payment": null, + "paymentInterval": null, "paymentLoading": false, + "paymentTimeout": 60000, "payments": Array [], "sendingPayment": false, "showSuccessPayScreen": false, @@ -23,7 +27,9 @@ Object { exports[`reducers paymentReducer should correctly receivePayments 1`] = ` Object { "payment": null, + "paymentInterval": null, "paymentLoading": false, + "paymentTimeout": 60000, "payments": Array [ 1, 2, @@ -36,7 +42,9 @@ Object { exports[`reducers paymentReducer should correctly sendPayment 1`] = ` Object { "payment": "foo", + "paymentInterval": null, "paymentLoading": false, + "paymentTimeout": 60000, "payments": Array [], "sendingPayment": false, "showSuccessPayScreen": false, @@ -46,7 +54,9 @@ Object { exports[`reducers paymentReducer should handle initial state 1`] = ` Object { "payment": null, + "paymentInterval": null, "paymentLoading": false, + "paymentTimeout": 60000, "payments": Array [], "sendingPayment": false, "showSuccessPayScreen": false,