From 645dd43bc97c001038a45d0457873d9230e1f760 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sun, 25 Oct 2020 21:17:51 +0000 Subject: [PATCH] fix(ui): keep activity spinner during loading --- .../ActivityActions/ActivityActions.js | 4 +- .../ActivityActions/ActivityRefresh.js | 25 +++++--- renderer/components/UI/ActionButton.js | 9 +-- .../containers/Activity/ActivityActions.js | 1 + renderer/reducers/activity/reducer.js | 64 +++++++------------ renderer/reducers/activity/selectors.js | 3 +- 6 files changed, 47 insertions(+), 59 deletions(-) diff --git a/renderer/components/Activity/ActivityActions/ActivityActions.js b/renderer/components/Activity/ActivityActions/ActivityActions.js index 4e11d30e194..ee05d5c9e1e 100644 --- a/renderer/components/Activity/ActivityActions/ActivityActions.js +++ b/renderer/components/Activity/ActivityActions/ActivityActions.js @@ -16,6 +16,7 @@ const ActivityActions = ({ changeFilter, reloadActivityHistory, updateSearchText, + isPageLoading, isCustomFilter, intl, ...rest @@ -39,7 +40,7 @@ const ActivityActions = ({ mx={3} /> - + @@ -51,6 +52,7 @@ ActivityActions.propTypes = { filters: PropTypes.array.isRequired, intl: intlShape.isRequired, isCustomFilter: PropTypes.bool, + isPageLoading: PropTypes.bool, reloadActivityHistory: PropTypes.func.isRequired, searchText: PropTypes.string, updateSearchText: PropTypes.func.isRequired, diff --git a/renderer/components/Activity/ActivityActions/ActivityRefresh.js b/renderer/components/Activity/ActivityActions/ActivityRefresh.js index 8fa2a3c99f3..cc2c9385bd4 100644 --- a/renderer/components/Activity/ActivityActions/ActivityRefresh.js +++ b/renderer/components/Activity/ActivityActions/ActivityRefresh.js @@ -1,21 +1,26 @@ import React from 'react' import PropTypes from 'prop-types' -import { injectIntl } from 'react-intl' +import { useIntl } from 'react-intl' import Refresh from 'components/Icon/Refresh' import { ActionButton } from 'components/UI' import messages from './messages' -const ActivityRefresh = injectIntl(({ intl, onClick, ...rest }) => ( - - - -)) +const ActivityRefresh = ({ isPageLoading, onClick, ...rest }) => { + const { formatMessage } = useIntl() + return ( + + + + ) +} ActivityRefresh.propTypes = { + isPageLoading: PropTypes.bool, onClick: PropTypes.func.isRequired, } diff --git a/renderer/components/UI/ActionButton.js b/renderer/components/UI/ActionButton.js index a1a653840df..8ed6368c794 100644 --- a/renderer/components/UI/ActionButton.js +++ b/renderer/components/UI/ActionButton.js @@ -16,7 +16,7 @@ StyledButton.propTypes = { active: PropTypes.bool, } -const ActionButton = ({ children, hint, onClick, timeout, ...rest }) => { +const ActionButton = ({ children, hint, isLoading, onClick, timeout = 1000, ...rest }) => { const [status, setStatus] = useState(null) const buttonRef = useRef() @@ -49,7 +49,7 @@ const ActionButton = ({ children, hint, onClick, timeout, ...rest }) => { variant="secondary" {...rest} > - {status === 'fetching' ? : children} + {status === 'fetching' || isLoading ? : children} ) } @@ -57,12 +57,9 @@ const ActionButton = ({ children, hint, onClick, timeout, ...rest }) => { ActionButton.propTypes = { children: PropTypes.node, hint: PropTypes.node, + isLoading: PropTypes.bool, onClick: PropTypes.func.isRequired, timeout: PropTypes.number, } -ActionButton.defaultProps = { - timeout: 1000, -} - export default ActionButton diff --git a/renderer/containers/Activity/ActivityActions.js b/renderer/containers/Activity/ActivityActions.js index b555b15ec0e..cc041504cf0 100644 --- a/renderer/containers/Activity/ActivityActions.js +++ b/renderer/containers/Activity/ActivityActions.js @@ -18,6 +18,7 @@ const mapStateToProps = state => ({ filters: activitySelectors.filters(state), searchText: activitySelectors.searchText(state), isCustomFilter: activitySelectors.isCustomFilter(state), + isPageLoading: activitySelectors.isPageLoading(state), }) export default connect(mapStateToProps, mapDispatchToProps)(ActivityActions) diff --git a/renderer/reducers/activity/reducer.js b/renderer/reducers/activity/reducer.js index e044641ac8d..930890bacf1 100644 --- a/renderer/reducers/activity/reducer.js +++ b/renderer/reducers/activity/reducer.js @@ -1,5 +1,4 @@ import { send } from 'redux-electron-ipc' -import groupBy from 'lodash/groupBy' import createReducer from '@zap/utils/createReducer' import { getIntl } from '@zap/i18n' import { mainLog } from '@zap/utils/log' @@ -12,7 +11,7 @@ import { fetchBalance } from 'reducers/balance' import { fetchChannels } from 'reducers/channels' import { fetchInfo, infoSelectors } from 'reducers/info' import { showError, showNotification } from 'reducers/notification' -import { createActivityPaginator, getItemType } from './utils' +import { createActivityPaginator } from './utils' import { hasNextPage, isPageLoading } from './selectors' import messages from './messages' import * as constants from './constants' @@ -77,22 +76,21 @@ 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 * and creates paginator if it's not initialized. * - * @param {Function} dispatch Reduc dispatcher. + * @param {{ + * invoiceHandler: function, + * paymentHandler: function, + * transactionHandler: function + * }} handlers Pagination handlers * @returns {Function} Paginator */ -export const getPaginator = dispatch => { +export const getPaginator = handlers => { if (!paginator) { - paginator = createActivityPaginator({ - invoiceHandler: items => dispatch(receiveInvoices(items)), - paymentHandler: items => dispatch(receivePayments(items)), - transactionHandler: items => dispatch(receiveTransactions(items)), - }) + paginator = createActivityPaginator(handlers) } return paginator } @@ -242,22 +240,12 @@ export const hideActivityModal = () => dispatch => { */ 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. + * @param {boolean} reload Boolean indicating wether to load first page. * @returns {(dispatch:Function, getState:Function) => Promise} Thunk */ export const loadPage = (reload = false) => async (dispatch, getState) => { @@ -269,36 +257,30 @@ export const loadPage = (reload = false) => async (dispatch, getState) => { await dispatch(fetchInfo()) const config = settingsSelectors.currentConfig(getState()) const blockHeight = infoSelectors.blockHeight(getState()) - const thisPaginator = getPaginator(dispatch) - - if (reload || hasNextPage(getState())) { - const { pageSize } = config.activity - const { items, hasNextPage: paginatorHasNextPage } = await thisPaginator(pageSize, blockHeight) - if (!reload) { - loadedPages += 1 - dispatch({ type: SET_HAS_NEXT_PAGE, value: paginatorHasNextPage }) - } - - const { invoices, payments, transactions } = groupBy(items, getItemType) + const handlers = { + invoiceHandler: items => items && dispatch(receiveInvoices(items)), + paymentHandler: items => items && dispatch(receivePayments(items)), + transactionHandler: items => items && dispatch(receiveTransactions(items)), + } + const thisPaginator = reload ? createActivityPaginator(handlers) : getPaginator(handlers) - invoices && dispatch(receiveInvoices(invoices)) - payments && dispatch(receivePayments(payments)) - transactions && dispatch(receiveTransactions(transactions)) + if (hasNextPage(getState())) { + const { pageSize } = config.activity + const { hasNextPage } = await thisPaginator(pageSize, blockHeight) + dispatch({ type: SET_HAS_NEXT_PAGE, value: hasNextPage }) } dispatch(setPageLoading(false)) } /** - * reloadPages - Reloads all already loaded activity pages. + * reloadActivityHead - Reloads activity head. * * @returns {(dispatch:Function) => Promise} Thunk */ -export const reloadPages = () => async dispatch => { - const pageCount = loadedPages - mainLog.debug(`reloading ${pageCount} activity pages`) - dispatch(resetPaginator()) +export const reloadActivityHead = () => async dispatch => { + mainLog.debug(`reloading activity pages`) await dispatch(loadPage(true)) } @@ -326,7 +308,7 @@ export const reloadActivityHistory = () => async dispatch => { dispatch({ type: FETCH_ACTIVITY_HISTORY }) try { await Promise.all([ - dispatch(reloadPages()), + dispatch(reloadActivityHead()), dispatch(fetchChannels()), dispatch(fetchBalance()), ]) diff --git a/renderer/reducers/activity/selectors.js b/renderer/reducers/activity/selectors.js index fd6c9c9f1af..67b215aba1d 100644 --- a/renderer/reducers/activity/selectors.js +++ b/renderer/reducers/activity/selectors.js @@ -278,11 +278,12 @@ export const isCustomFilter = createSelector(filter, currentFilter => { * All selectors to export. */ export default { + errorDialogDetails, filter, filters, searchText, hasNextPage, - errorDialogDetails, + isPageLoading, isErrorDialogOpen, currentActivity, activityModalItem,