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

Commit

Permalink
fix(ui): keep activity spinner during loading
Browse files Browse the repository at this point in the history
  • Loading branch information
mrfelton committed Oct 25, 2020
1 parent e1dfefd commit 645dd43
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const ActivityActions = ({
changeFilter,
reloadActivityHistory,
updateSearchText,
isPageLoading,
isCustomFilter,
intl,
...rest
Expand All @@ -39,7 +40,7 @@ const ActivityActions = ({
mx={3}
/>

<ActivityRefresh mx={3} onClick={reloadActivityHistory} />
<ActivityRefresh isPageLoading={isPageLoading} mx={3} onClick={reloadActivityHistory} />
</Flex>
</Flex>
</Card>
Expand All @@ -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,
Expand Down
25 changes: 15 additions & 10 deletions renderer/components/Activity/ActivityActions/ActivityRefresh.js
Original file line number Diff line number Diff line change
@@ -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 }) => (
<ActionButton
hint={intl.formatMessage({ ...messages.refresh_button_hint })}
onClick={onClick}
{...rest}
>
<Refresh height="16px" width="16px" />
</ActionButton>
))
const ActivityRefresh = ({ isPageLoading, onClick, ...rest }) => {
const { formatMessage } = useIntl()
return (
<ActionButton
hint={formatMessage({ ...messages.refresh_button_hint })}
isLoading={isPageLoading}
onClick={onClick}
{...rest}
>
<Refresh height="16px" width="16px" />
</ActionButton>
)
}

ActivityRefresh.propTypes = {
isPageLoading: PropTypes.bool,
onClick: PropTypes.func.isRequired,
}

Expand Down
9 changes: 3 additions & 6 deletions renderer/components/UI/ActionButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -49,20 +49,17 @@ const ActionButton = ({ children, hint, onClick, timeout, ...rest }) => {
variant="secondary"
{...rest}
>
{status === 'fetching' ? <Spinner height="16px" width="16px" /> : children}
{status === 'fetching' || isLoading ? <Spinner height="16px" width="16px" /> : children}
</StyledButton>
)
}

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
1 change: 1 addition & 0 deletions renderer/containers/Activity/ActivityActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
64 changes: 23 additions & 41 deletions renderer/reducers/activity/reducer.js
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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'
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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<void>} Thunk
*/
export const loadPage = (reload = false) => async (dispatch, getState) => {
Expand All @@ -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<void>} 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))
}

Expand Down Expand Up @@ -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()),
])
Expand Down
3 changes: 2 additions & 1 deletion renderer/reducers/activity/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 645dd43

Please sign in to comment.