From ca84cfc8a2f681eb46d564aa0738cb8f9485848b Mon Sep 17 00:00:00 2001 From: elforjani3 Date: Mon, 8 Mar 2021 16:17:13 +0200 Subject: [PATCH] fix(exchangeRate): fix pagination & add sorting. --- .../ExchangeRates/ExchangeRateTable.js | 46 +++++-- .../ExchangeRates/ExchangeRatesList.js | 17 ++- .../ExchangeRates/ExchangeRatesProvider.js | 14 ++- .../ExchangeRates/withExchangeRates.js | 20 +-- .../ExchangeRates/withExchangeRatesActions.js | 24 +--- client/src/hooks/query/exchangeRates.js | 35 +++--- .../store/ExchangeRate/exchange.actions.js | 118 +----------------- .../store/ExchangeRate/exchange.reducer.js | 87 +------------ .../store/ExchangeRate/exchange.selector.js | 47 ++----- .../src/store/ExchangeRate/exchange.type.js | 10 +- 10 files changed, 115 insertions(+), 303 deletions(-) diff --git a/client/src/containers/ExchangeRates/ExchangeRateTable.js b/client/src/containers/ExchangeRates/ExchangeRateTable.js index 8813fa2e2..eb89144b2 100644 --- a/client/src/containers/ExchangeRates/ExchangeRateTable.js +++ b/client/src/containers/ExchangeRates/ExchangeRateTable.js @@ -1,14 +1,17 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { DataTable } from 'components'; import TableSkeletonRows from 'components/Datatable/TableSkeletonRows'; +import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton'; import { useExchangeRatesContext } from './ExchangeRatesProvider'; import { useExchangeRatesTableColumns, ActionMenuList } from './components'; +import withExchangeRates from './withExchangeRates'; +import withExchangeRatesActions from './withExchangeRatesActions'; + import withDialogActions from 'containers/Dialog/withDialogActions'; import withAlertActions from 'containers/Alert/withAlertActions'; - import { compose } from 'utils'; /** @@ -23,6 +26,12 @@ function ExchangeRateTable({ // #withAlertActions openAlert, + + // #withExchangeRatesActions + setExchangeRateTableState, + + // #withExchangeRates + exchangeRatesTableState, }) { const { isExchangeRatesFetching, @@ -48,28 +57,51 @@ function ExchangeRateTable({ }); }; + const handleFetchData = useCallback( + ({ pageSize, pageIndex, sortBy }) => { + setExchangeRateTableState({ + pageIndex, + pageSize, + sortBy, + }); + }, + [setExchangeRateTableState], + ); + return ( ); } -export default compose(withDialogActions, withAlertActions)(ExchangeRateTable); +export default compose( + withDialogActions, + withAlertActions, + withExchangeRates(({ exchangeRatesTableState }) => ({ + exchangeRatesTableState, + })), + withExchangeRatesActions, +)(ExchangeRateTable); diff --git a/client/src/containers/ExchangeRates/ExchangeRatesList.js b/client/src/containers/ExchangeRates/ExchangeRatesList.js index e4c040d2a..97e10d70b 100644 --- a/client/src/containers/ExchangeRates/ExchangeRatesList.js +++ b/client/src/containers/ExchangeRates/ExchangeRatesList.js @@ -1,4 +1,5 @@ import React from 'react'; +import { compose } from 'utils'; import { DashboardContentTable, DashboardPageContent } from 'components'; @@ -7,13 +8,20 @@ import ExchangeRateActionsBar from './ExchangeRateActionsBar'; import { ExchangeRatesProvider } from './ExchangeRatesProvider'; import ExchangeRatesAlerts from './ExchangeRatesAlerts'; +import withExchangeRates from './withExchangeRates'; +import { transformTableStateToQuery } from 'utils'; /** * Exchange Rates list. */ -export default function ExchangeRatesList() { +function ExchangeRatesList({ + // #withExchangeRates + exchangeRatesTableState, +}) { return ( - + @@ -25,3 +33,8 @@ export default function ExchangeRatesList() { ); } +export default compose( + withExchangeRates(({ exchangeRatesTableState }) => ({ + exchangeRatesTableState, + })), +)(ExchangeRatesList); diff --git a/client/src/containers/ExchangeRates/ExchangeRatesProvider.js b/client/src/containers/ExchangeRates/ExchangeRatesProvider.js index f296ff1c9..1889a8250 100644 --- a/client/src/containers/ExchangeRates/ExchangeRatesProvider.js +++ b/client/src/containers/ExchangeRates/ExchangeRatesProvider.js @@ -1,4 +1,6 @@ import React, { createContext } from 'react'; +import { transformTableQueryToParams } from 'utils'; + import DashboardInsider from 'components/Dashboard/DashboardInsider'; import { useExchangeRates } from 'hooks/query'; @@ -9,10 +11,15 @@ const ExchangesRatesContext = createContext(); */ function ExchangeRatesProvider({ query, ...props }) { const { - data: { exchangesRates, pagination }, + data: { exchangesRates, pagination, filterMeta }, isFetching: isExchangeRatesFetching, isLoading: isExchangeRatesLoading, - } = useExchangeRates(); + } = useExchangeRates( + { + ...transformTableQueryToParams(query), + }, + { keepPreviousData: true }, + ); const state = { isExchangeRatesFetching, @@ -20,11 +27,10 @@ function ExchangeRatesProvider({ query, ...props }) { exchangesRates, pagination, - query, }; return ( - + ); diff --git a/client/src/containers/ExchangeRates/withExchangeRates.js b/client/src/containers/ExchangeRates/withExchangeRates.js index fa411f372..17a3bcf03 100644 --- a/client/src/containers/ExchangeRates/withExchangeRates.js +++ b/client/src/containers/ExchangeRates/withExchangeRates.js @@ -1,24 +1,12 @@ import { connect } from 'react-redux'; -import { - getExchangeRatesList, - getExchangeRatePaginationMetaFactory, - getExchangeRatesTableQueryFactory, -} from 'store/ExchangeRate/exchange.selector'; +import { getExchangeRatesTableStateFactory } from 'store/ExchangeRate/exchange.selector'; export default (mapState) => { - const getExchangeRatesPaginationMeta = getExchangeRatePaginationMetaFactory(); - + const getExchangeRatesTableState = getExchangeRatesTableStateFactory(); + const mapStateToProps = (state, props) => { - const query = getExchangeRatesTableQueryFactory(state, props); - const mapped = { - exchangeRatesList: getExchangeRatesList(state, props), - exchangeRatesLoading: state.exchangeRates.loading, - exchangeRatesPageination: getExchangeRatesPaginationMeta( - state, - props, - query, - ), + exchangeRatesTableState: getExchangeRatesTableState(state, props), }; return mapState ? mapState(mapped, state, props) : mapped; }; diff --git a/client/src/containers/ExchangeRates/withExchangeRatesActions.js b/client/src/containers/ExchangeRates/withExchangeRatesActions.js index c439a6344..61eedf4bf 100644 --- a/client/src/containers/ExchangeRates/withExchangeRatesActions.js +++ b/client/src/containers/ExchangeRates/withExchangeRatesActions.js @@ -1,23 +1,9 @@ import { connect } from 'react-redux'; -import { - submitExchangeRate, - fetchExchangeRates, - deleteExchangeRate, - editExchangeRate, - deleteBulkExchangeRates -} from 'store/ExchangeRate/exchange.actions'; +import { setExchangeRateTableState } from 'store/ExchangeRate/exchange.actions'; -const mapActionsToProps = (dispatch) => ({ - requestSubmitExchangeRate: (form) => dispatch(submitExchangeRate({ form })), - requestFetchExchangeRates: () => dispatch(fetchExchangeRates()), - requestDeleteExchangeRate: (id) => dispatch(deleteExchangeRate(id)), - requestEditExchangeRate: (id, form) => dispatch(editExchangeRate(id, form)), - requestDeleteBulkExchangeRates:(ids)=>dispatch(deleteBulkExchangeRates({ids})), - addExchangeRatesTableQueries: (queries) => - dispatch({ - type: 'ExchangeRates_TABLE_QUERIES_ADD', - queries, - }), +export const mapDispatchToProps = (dispatch) => ({ + setExchangeRateTableState: (queries) => + dispatch(setExchangeRateTableState(queries)), }); -export default connect(null, mapActionsToProps); +export default connect(null, mapDispatchToProps); diff --git a/client/src/hooks/query/exchangeRates.js b/client/src/hooks/query/exchangeRates.js index 2493143f2..7f2d4fd6c 100644 --- a/client/src/hooks/query/exchangeRates.js +++ b/client/src/hooks/query/exchangeRates.js @@ -1,7 +1,13 @@ import { useQuery, useMutation, useQueryClient } from 'react-query'; import { defaultTo } from 'lodash'; +import { transformPagination, transformResponse } from 'utils'; import useApiRequest from '../useRequest'; +const defaultPagination = { + pageSize: 12, + page: 0, + pagesCount: 0, +}; /** * Creates a new exchange rate. */ @@ -50,14 +56,6 @@ export function useDeleteExchangeRate(props) { }); } -// Transforms items categories. -const transformExchangesRates = (response) => { - return { - exchangesRates: response.data.exchange_rates.results, - pagination: response.data.exchange_rates.pagination, - }; -}; - /** * Retrieve the exchange rate list. */ @@ -66,18 +64,27 @@ export function useExchangeRates(query, props) { const states = useQuery( ['EXCHANGES_RATES', query], - () => - apiRequest.get('exchange_rates', { params: { query } }).then( - transformExchangesRates, - ), - props, + () => apiRequest.get('exchange_rates', { params: query }), + { + select: (res) => ({ + exchangesRates: res.data.exchange_rates.results, + pagination: transformPagination(res.data.exchange_rates.pagination), + filterMeta: res.data.filter_meta, + }), + ...props, + }, ); return { ...states, data: defaultTo(states.data, { exchangesRates: [], - pagination: {}, + pagination: { + page: 1, + pageSize: 12, + total: 0, + }, + filterMeta: {}, }), }; } diff --git a/client/src/store/ExchangeRate/exchange.actions.js b/client/src/store/ExchangeRate/exchange.actions.js index 072a17332..dc2e4213e 100644 --- a/client/src/store/ExchangeRate/exchange.actions.js +++ b/client/src/store/ExchangeRate/exchange.actions.js @@ -1,116 +1,8 @@ -import ApiService from 'services/ApiService'; import t from 'store/types'; -export const fetchExchangeRates = () => { - return (dispatch) => - new Promise((resolve, reject) => { - dispatch({ - type: t.EXCHANGE_RATE_TABLE_LOADING, - payload: { - loading: true, - }, - }); - - ApiService.get('exchange_rates') - .then((response) => { - dispatch({ - type: t.EXCHANGE_RATES_PAGE_SET, - payload: { - exchange_rates: response.data.exchange_rates.results, - pagination: response.data.exchange_rates.pagination, - customViewId: response.data.exchange_rates.customViewId || -1, - }, - }); - dispatch({ - type: t.EXCHANGE_RATE_LIST_SET, - exchange_rates: response.data.exchange_rates.results, - }); - - dispatch({ - type: t.EXCHANGE_RATES_PAGINATION_SET, - payload: { - pagination: response.data.exchange_rates.pagination, - customViewId: response.data.customViewId || -1, - }, - }); - dispatch({ - type: t.EXCHANGE_RATE_TABLE_LOADING, - payload: { - loading: false, - }, - }); - resolve(response); - }) - .catch((error) => { - reject(error); - }); - }); -}; - -export const submitExchangeRate = ({ form }) => { - return (dispatch) => - new Promise((resolve, reject) => { - ApiService.post('exchange_rates', form) - .then((response) => { - resolve(response); - }) - .catch((error) => { - const { response } = error; - const { data } = response; - reject(data?.errors); - }); - }); -}; - -export const deleteExchangeRate = (id) => { - return (dispatch) => - new Promise((resolve, reject) => { - ApiService.delete(`exchange_rates/${id}`) - .then((response) => { - dispatch({ type: t.EXCHANGE_RATE_DELETE, id }); - resolve(response); - }) - .catch((error) => { - reject(error.response.data.errors || []); - }); - }); -}; - -export const editExchangeRate = (id, form) => { - return (dispatch) => - new Promise((resolve, reject) => { - ApiService.post(`exchange_rates/${id}`, form) - .then((response) => { - dispatch({ type: t.CLEAR_EXCHANGE_RATE_FORM_ERRORS }); - resolve(response); - }) - .catch((error) => { - const { response } = error; - const { data } = response; - const { errors } = data; - - dispatch({ type: t.CLEAR_EXCHANGE_RATE_FORM_ERRORS }); - if (errors) { - dispatch({ type: t.CLEAR_EXCHANGE_RATE_FORM_ERRORS, errors }); - } - reject(data?.errors); - }); - }); -}; - -export const deleteBulkExchangeRates = ({ ids }) => { - return (dispatch) => - new Promise((resolve, reject) => { - ApiService.delete(`exchange_rates/bulk`, { params: { ids } }) - .then((response) => { - dispatch({ - type: t.EXCHANGE_RATES_BULK_DELETE, - payload: { ids }, - }); - resolve(response); - }) - .catch((error) => { - reject(error); - }); - }); +export const setExchangeRateTableState = (queries) => { + return { + type: t.EXCHANGE_RATES_TABLE_STATE_SET, + payload: { queries }, + }; }; diff --git a/client/src/store/ExchangeRate/exchange.reducer.js b/client/src/store/ExchangeRate/exchange.reducer.js index 94ef93516..3b746a127 100644 --- a/client/src/store/ExchangeRate/exchange.reducer.js +++ b/client/src/store/ExchangeRate/exchange.reducer.js @@ -1,88 +1,13 @@ import { createReducer } from '@reduxjs/toolkit'; -import { createTableQueryReducers } from 'store/queryReducers'; -import t from 'store/types'; +import { createTableStateReducers } from 'store/tableState.reducer'; const initialState = { - exchangeRates: {}, - loading: false, - views: {}, - tableQuery: { - page_size: 5, - page: 1, + tableState: { + pageSize: 12, + pageIndex: 0, }, - currentViewId: -1, }; -const reducer = createReducer(initialState, { - [t.EXCHANGE_RATE_LIST_SET]: (state, action) => { - const _exchangeRates = {}; - action.exchange_rates.forEach((exchange_rate) => { - _exchangeRates[exchange_rate.id] = exchange_rate; - }); - - state.exchangeRates = { - ...state.exchangeRates, - ..._exchangeRates, - }; - }, - - [t.EXCHANGE_RATE_TABLE_LOADING]: (state, action) => { - const { loading } = action.payload; - state.loading = loading; - }, - - [t.EXCHANGE_RATES_PAGE_SET]: (state, action) => { - const { customViewId, exchange_rates, pagination } = action.payload; - - const viewId = customViewId || -1; - const view = state.views[viewId] || {}; - state.views[viewId] = { - ...view, - pages: { - ...(state.views?.[viewId]?.pages || {}), - [pagination.page]: { - ids: exchange_rates.map((i) => i.id), - }, - }, - }; - }, - - [t.EXCHANGE_RATES_PAGINATION_SET]: (state, action) => { - const { pagination, customViewId } = action.payload; - - const mapped = { - pageSize: parseInt(pagination.pageSize, 10), - page: parseInt(pagination.page, 10), - total: parseInt(pagination.total, 10), - }; - const paginationMeta = { - ...mapped, - pagesCount: Math.ceil(mapped.total / mapped.pageSize), - pageIndex: Math.max(mapped.page - 1, 0), - }; - - state.views = { - ...state.views, - [customViewId]: { - ...(state.views?.[customViewId] || {}), - paginationMeta, - }, - }; - }, - - [t.EXCHANGE_RATES_BULK_DELETE]: (state, action) => { - const { ids } = action.payload; - ids.forEach((id) => { - if (typeof state.exchangeRates[id] !== 'undefined') { - delete state.exchangeRates[id]; - } - }); - }, - [t.EXCHANGE_RATE_DELETE]: (state, action) => { - if (typeof state.exchangeRates[action.id] !== 'undefined') { - delete state.exchangeRates[action.id]; - } - }, +export default createReducer(initialState, { + ...createTableStateReducers('EXCHANGE_RATES'), }); - -export default createTableQueryReducers('exchange_rates', reducer); diff --git a/client/src/store/ExchangeRate/exchange.selector.js b/client/src/store/ExchangeRate/exchange.selector.js index cc7f726c1..49f0659b8 100644 --- a/client/src/store/ExchangeRate/exchange.selector.js +++ b/client/src/store/ExchangeRate/exchange.selector.js @@ -1,47 +1,18 @@ -import { createSelector } from 'reselect'; -import { - pickItemsFromIds, - getItemById, - paginationLocationQuery, -} from 'store/selectors'; +import { createDeepEqualSelector } from 'utils'; +import { paginationLocationQuery } from 'store/selectors'; -const exchangeRateItemsSelector = (state) => state.exchangeRates.exchangeRates; -const exchangeRateIdPropSelector = (state, props) => props.exchangeRateId; -const exchangeRateTableQuery = (state) => state.exchangeRates.tableQuery; - -const exchangeRatesCurrentViewSelector = (state, props) => { - const viewId = state.exchangeRates.currentViewId; - return state.exchangeRates.views?.[viewId]; +const exchangeRateTableState = (state) => { + return state.exchangeRates.tableState; }; -export const getExchangeRatesList = createSelector( - exchangeRateItemsSelector, - (exchangeRateItems) => { - return Object.values(exchangeRateItems); - }, -); - -export const getExchangeRateById = createSelector( - exchangeRateItemsSelector, - exchangeRateIdPropSelector, - (exchangeRates, exchangeRateId) => { - return getItemById(exchangeRates, exchangeRateId); - }, -); - -export const getExchangeRatePaginationMetaFactory = () => - createSelector(exchangeRatesCurrentViewSelector, (exchangeRateView) => { - return exchangeRateView?.paginationMeta || {}; - }); - -export const getExchangeRatesTableQueryFactory = () => - createSelector( +export const getExchangeRatesTableStateFactory = () => + createDeepEqualSelector( paginationLocationQuery, - exchangeRateTableQuery, - (locationQuery, tableQuery) => { + exchangeRateTableState, + (locationQuery, tableState) => { return { ...locationQuery, - ...tableQuery, + ...tableState, }; }, ); diff --git a/client/src/store/ExchangeRate/exchange.type.js b/client/src/store/ExchangeRate/exchange.type.js index 85807c21e..b5a99dd87 100644 --- a/client/src/store/ExchangeRate/exchange.type.js +++ b/client/src/store/ExchangeRate/exchange.type.js @@ -1,11 +1,3 @@ export default { - EXCHANGE_RATE_DATA_TABLE: 'EXCHANGE_RATE_DATA_TABLE', - EXCHANGE_RATE_DELETE: 'EXCHANGE_RATE_DELETE', - EXCHANGE_RATE_LIST_SET: 'EXCHANGE_RATE_LIST_SET', - CLEAR_EXCHANGE_RATE_FORM_ERRORS: 'CLEAR_EXCHANGE_RATE_FORM_ERRORS', - ExchangeRates_TABLE_QUERIES_ADD: 'ExchangeRates_TABLE_QUERIES_ADD', - EXCHANGE_RATE_TABLE_LOADING: 'EXCHANGE_RATE_TABLE_LOADING', - EXCHANGE_RATES_BULK_DELETE: 'EXCHANGE_RATES_BULK_DELETE', - EXCHANGE_RATES_PAGE_SET: 'EXCHANGE_RATES_PAGE_SET', - EXCHANGE_RATES_PAGINATION_SET: 'EXCHANGE_RATES_PAGINATION_SET', + EXCHANGE_RATES_TABLE_STATE_SET: 'EXCHANGE_RATES/TABLE_STATE_SET', };