Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Fix activity reloading #3525

Merged
merged 3 commits into from
May 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions renderer/components/Activity/Activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const Activity = props => {
errorDialogDetails,
currentActivity,
showNotification,
loadNextPage,
loadPage,
intl,
} = props

Expand All @@ -35,7 +35,7 @@ const Activity = props => {

const isRowLoaded = ({ index }) => Boolean(currentActivity[index])

const loadMoreRows = () => loadNextPage()
const loadMoreRows = () => loadPage()
const renderActivityList = () => {
return (
<InfiniteLoader
Expand Down Expand Up @@ -90,7 +90,7 @@ Activity.propTypes = {
hideErrorDetailsDialog: PropTypes.func.isRequired,
intl: intlShape.isRequired,
isErrorDialogOpen: PropTypes.bool,
loadNextPage: PropTypes.func.isRequired,
loadPage: PropTypes.func.isRequired,
showNotification: PropTypes.func.isRequired,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const ActivityActions = ({
filters,
searchText,
changeFilter,
fetchActivityHistory,
reloadActivityHistory,
updateSearchText,
isCustomFilter,
intl,
Expand All @@ -39,19 +39,19 @@ const ActivityActions = ({
mx={3}
/>

<ActivityRefresh mx={3} onClick={fetchActivityHistory} />
<ActivityRefresh mx={3} onClick={reloadActivityHistory} />
</Flex>
</Flex>
</Card>
)

ActivityActions.propTypes = {
changeFilter: PropTypes.func.isRequired,
fetchActivityHistory: PropTypes.func.isRequired,
filter: PropTypes.object.isRequired,
filters: PropTypes.array.isRequired,
intl: intlShape.isRequired,
isCustomFilter: PropTypes.bool,
reloadActivityHistory: PropTypes.func.isRequired,
searchText: PropTypes.string,
updateSearchText: PropTypes.func.isRequired,
}
Expand Down
19 changes: 12 additions & 7 deletions renderer/components/App/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ const App = ({
modals,
redirectPayReq,
updateAutopilotNodeScores,
fetchActivityHistory,
initActivityHistory,
setIsWalletOpen,
fetchDescribeNetwork,
fetchPeers,
fetchTransactions,
setModals,
Expand All @@ -51,8 +52,8 @@ const App = ({
* node data quite frequently but as time goes on the frequency is reduced to a max of PEERS_MAX_REFETCH_INTERVAL
*/
appScheduler.addTask({
task: fetchPeers,
taskId: 'fetchPeers',
task: () => fetchDescribeNetwork() && fetchPeers(),
taskId: 'fetchNetworkData',
baseDelay: PEERS_INITIAL_REFETCH_INTERVAL,
maxDelay: PEERS_MAX_REFETCH_INTERVAL,
backoff: PEERS_REFETCH_BACKOFF_SCHEDULE,
Expand All @@ -73,15 +74,17 @@ const App = ({
return () => {
appScheduler.removeAllTasks()
}
}, [fetchPeers, fetchTransactions, updateAutopilotNodeScores])
}, [fetchDescribeNetwork, fetchPeers, fetchTransactions, updateAutopilotNodeScores])

useEffect(() => {
// Set wallet open state.
setIsWalletOpen(true)
// fetch data from lnd.
fetchActivityHistory()
initActivityHistory()
// fetch node info.
fetchPeers()
// fetch network info
fetchDescribeNetwork()
// Update autopilot node scores.
updateAutopilotNodeScores()
fetchSuggestedNodes()
Expand All @@ -93,7 +96,8 @@ const App = ({
finishLnurlWithdrawal()
}
}, [
fetchActivityHistory,
initActivityHistory,
fetchDescribeNetwork,
fetchPeers,
fetchSuggestedNodes,
initBackupService,
Expand Down Expand Up @@ -128,11 +132,12 @@ const App = ({
}

App.propTypes = {
fetchActivityHistory: PropTypes.func.isRequired,
fetchDescribeNetwork: PropTypes.func.isRequired,
fetchPeers: PropTypes.func.isRequired,
fetchSuggestedNodes: PropTypes.func.isRequired,
fetchTransactions: PropTypes.func.isRequired,
finishLnurlWithdrawal: PropTypes.func.isRequired,
initActivityHistory: PropTypes.func.isRequired,
initBackupService: PropTypes.func.isRequired,
initTickers: PropTypes.func.isRequired,
isAppReady: PropTypes.bool.isRequired,
Expand Down
4 changes: 2 additions & 2 deletions renderer/containers/Activity/Activity.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { connect } from 'react-redux'
import { activitySelectors, loadNextPage, ERROR_DETAILS_DIALOG_ID } from 'reducers/activity'
import { activitySelectors, loadPage, ERROR_DETAILS_DIALOG_ID } from 'reducers/activity'
import { showNotification } from 'reducers/notification'
import { modalSelectors, closeDialog } from 'reducers/modal'
import Activity from 'components/Activity'
Expand All @@ -15,7 +15,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = {
hideErrorDetailsDialog,
showNotification,
loadNextPage,
loadPage,
}

export default connect(mapStateToProps, mapDispatchToProps)(Activity)
4 changes: 2 additions & 2 deletions renderer/containers/Activity/ActivityActions.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { connect } from 'react-redux'
import {
changeFilter,
fetchActivityHistory,
reloadActivityHistory,
updateSearchText,
activitySelectors,
} from 'reducers/activity'
import ActivityActions from 'components/Activity/ActivityActions'

const mapDispatchToProps = {
changeFilter,
fetchActivityHistory,
reloadActivityHistory,
updateSearchText,
}

Expand Down
6 changes: 4 additions & 2 deletions renderer/containers/App/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react'
import { connect } from 'react-redux'
import { fetchPeers } from 'reducers/peers'
import { fetchDescribeNetwork } from 'reducers/network'
import { setIsWalletOpen } from 'reducers/wallet'
import { updateAutopilotNodeScores } from 'reducers/autopilot'
import { fetchActivityHistory } from 'reducers/activity'
import { initActivityHistory } from 'reducers/activity'
import { fetchTransactions } from 'reducers/transaction'
import { appSelectors } from 'reducers/app'
import { finishLnurlWithdrawal, paySelectors } from 'reducers/pay'
Expand All @@ -24,9 +25,10 @@ const mapStateToProps = state => ({
})

const mapDispatchToProps = {
fetchDescribeNetwork,
fetchPeers,
updateAutopilotNodeScores,
fetchActivityHistory,
initActivityHistory,
setIsWalletOpen,
fetchTransactions,
setModals,
Expand Down
92 changes: 66 additions & 26 deletions renderer/reducers/activity/reducer.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { send } from 'redux-electron-ipc'
import groupBy from 'lodash/groupBy'
import range from 'lodash/range'
import config from 'config'
import createReducer from '@zap/utils/createReducer'
import { getIntl } from '@zap/i18n'
import { mainLog } from '@zap/utils/log'
import { openModal, closeModal } from 'reducers/modal'
import { fetchDescribeNetwork } from 'reducers/network'
import { receiveTransactions } from 'reducers/transaction'
import { receivePayments } from 'reducers/payment'
import { receiveInvoices } from 'reducers/invoice'
import { fetchBalance } from 'reducers/balance'
import { showError, showNotification } from 'reducers/notification'
import { fetchChannels } from 'reducers/channels'
import { createActivityPaginator } from './utils'
import { showError, showNotification } from 'reducers/notification'
import { createActivityPaginator, getItemType } from './utils'
import { hasNextPage } from './selectors'
import messages from './messages'
import * as constants from './constants'
Expand Down Expand Up @@ -73,6 +74,7 @@ const initialState = {
// activity paginator object. must be reset for each wallet login
/** @type {Function | null} */
let paginator = null
let loadedPages = 0

/**
* getPaginator - Returns current activity paginator object. This acts as a singleton
Expand Down Expand Up @@ -202,60 +204,98 @@ export const hideActivityModal = () => dispatch => {
}

/**
* loadNextPage - Loads next activity page if it's available.
* resetActivity - Reset activity history.
*
* @returns {() => void} Thunk
*/
export const resetActivity = () => () => {
paginator = null
loadedPages = 0
}

/**
* resetPaginator - Reset activity paginator.
*
* @returns {() => void} Thunk
*/
export const resetPaginator = () => () => {
paginator = null
}

/**
* loadPage - Loads next activity page if it's available.
*
* @param {boolean} reload Boolean indicating if this page load is part of a reload.
* @returns {(dispatch:Function, getState:Function) => Promise<void>} Thunk
*/
export const loadNextPage = () => async (dispatch, getState) => {
export const loadPage = (reload = false) => async (dispatch, getState) => {
const thisPaginator = getPaginator()
if (hasNextPage(getState())) {
const { items, hasNextPage: paginatorHasNextPage } = await thisPaginator(
config.activity.pageSize
)
if (reload || hasNextPage(getState())) {
const { pageSize } = config.activity
const { items, hasNextPage: paginatorHasNextPage } = await thisPaginator(pageSize)

const getItemType = item => {
if (item.destAddresses) {
return 'transactions'
}
if ('addIndex' in item) {
return 'invoices'
}
return 'payments'
if (!reload) {
loadedPages += 1
dispatch({ type: SET_HAS_NEXT_PAGE, value: paginatorHasNextPage })
}

const { invoices, payments, transactions } = groupBy(items, getItemType)
dispatch({ type: SET_HAS_NEXT_PAGE, value: paginatorHasNextPage })
invoices && dispatch(receiveInvoices(invoices))
payments && dispatch(receivePayments(payments))
transactions && dispatch(receiveTransactions(transactions))
}
}

/**
* fetchActivityHistory - Fetch user activity history, including Balance, Payments, Invoices, Transactions etc.
* reloadPages - Reloads all already loaded activity pages.
*
* @returns {(dispatch:Function) => Promise<void>} Thunk
*/
export const reloadPages = () => async dispatch => {
const pageCount = loadedPages
mainLog.debug(`reloading ${pageCount} activity pages`)
dispatch(resetPaginator())

// eslint-disable-next-line no-unused-vars
for (const page of range(pageCount)) {
mainLog.debug(`reloading activity page ${page}`)
// eslint-disable-next-line no-await-in-loop
await dispatch(loadPage(true))
}
}

/**
* initActivityHistory - Load user activity history.
*
* @returns {(dispatch:Function) => void} Thunk
*/
export const fetchActivityHistory = () => dispatch => {
export const initActivityHistory = () => async dispatch => {
dispatch({ type: FETCH_ACTIVITY_HISTORY })
try {
dispatch(fetchDescribeNetwork())
await dispatch(loadPage())
dispatch(fetchChannels())
dispatch(fetchBalance())
dispatch(loadNextPage())
dispatch({ type: FETCH_ACTIVITY_HISTORY_SUCCESS })
} catch (error) {
dispatch({ type: FETCH_ACTIVITY_HISTORY_FAILURE, error })
}
}

/**
* resetActivity - Reset user activity history.
* reloadActivityHistory - Reload activity history.
*
* @returns {() => void} Thunk
* @returns {(dispatch:Function) => void} Thunk
*/
export const resetActivity = () => () => {
paginator = null
export const reloadActivityHistory = () => async dispatch => {
dispatch({ type: FETCH_ACTIVITY_HISTORY })
try {
await dispatch(reloadPages())
dispatch(fetchChannels())
dispatch(fetchBalance())
dispatch({ type: FETCH_ACTIVITY_HISTORY_SUCCESS })
} catch (error) {
dispatch({ type: FETCH_ACTIVITY_HISTORY_FAILURE, error })
}
}

// ------------------------------------
Expand Down
16 changes: 16 additions & 0 deletions renderer/reducers/activity/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,19 @@ export const createActivityPaginator = () => {

return combinePaginators(itemSorter, fetchInvoices, fetchPayments, fetchTransactions)
}

/**
* getItemType - Determine an activity item type.
*
* @param {object<string, any>} item Activity item
* @returns {string} Item type
*/
export const getItemType = item => {
if (item.destAddresses) {
return 'transactions'
}
if ('addIndex' in item) {
return 'invoices'
}
return 'payments'
}
16 changes: 9 additions & 7 deletions renderer/reducers/invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,18 +208,20 @@ export const createInvoiceFailure = error => dispatch => {
export const receiveInvoiceData = invoice => dispatch => {
dispatch({ type: UPDATE_INVOICE, invoice })

// Fetch new balance
dispatch(fetchBalance())
const decoratedInvoice = decorateInvoice(invoice)

// Fetch updated channels.
dispatch(fetchChannels())
if (decoratedInvoice.isSettled) {
// Fetch new balance
dispatch(fetchBalance())

// Fetch updated channels.
dispatch(fetchChannels())

if (invoice.isSettled) {
const intl = getIntl()
// HTML 5 desktop notification for the invoice update
const intl = getIntl()
const notifTitle = intl.formatMessage(messages.invoice_receive_title)
const notifBody = intl.formatMessage(
invoice.isKeysend ? messages.keysend_receive_body : messages.invoice_receive_body
decoratedInvoice.isKeysend ? messages.keysend_receive_body : messages.invoice_receive_body
)

showSystemNotification(notifTitle, { body: notifBody })
Expand Down