feat: Pagination component.

This commit is contained in:
Ahmed Bouhuolia
2020-06-21 19:21:27 +02:00
parent 3e15cd42c8
commit 15bcd55979
19 changed files with 668 additions and 167 deletions

View File

@@ -11,7 +11,7 @@ import {
Position,
Tag,
} from '@blueprintjs/core';
import { useParams } from 'react-router-dom';
import { withRouter, useParams } from 'react-router-dom';
import { FormattedMessage as T, useIntl } from 'react-intl';
import moment from 'moment';
@@ -29,18 +29,21 @@ import withViewDetails from 'containers/Views/withViewDetails';
import withManualJournals from 'containers/Accounting/withManualJournals';
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
function ManualJournalsDataTable({
loading,
manualJournals,
// #withManualJournals
manualJournalsCurrentPage,
manualJournalsLoading,
manualJournalsPagination,
manualJournalsTableQuery,
// #withDashboardActions
changeCurrentView,
changePageSubtitle,
setTopbarEditView,
// #withViewDetails
viewId,
viewMeta,
@@ -96,27 +99,6 @@ function ManualJournalsDataTable({
[onDeleteJournal],
);
// const actionMenuList = (journal) => (
// <Menu>
// <MenuItem text={<T id={'view_details'} />} />
// <MenuDivider />
// {!journal.status && (
// <MenuItem
// text={<T id={'publish_journal'} />}
// onClick={handlePublishJournal(journal)}
// />
// )}
// <MenuItem
// text={<T id={'edit_journal'} />}
// onClick={handleEditJournal(journal)}
// />
// <MenuItem
// text={<T id={'delete_journal'} />}
// intent={Intent.DANGER}
// onClick={handleDeleteJournal(journal)}
// />
// </Menu>
// );
const actionMenuList = useCallback(
(journal) => (
<Menu>
@@ -171,13 +153,9 @@ function ManualJournalsDataTable({
Header: formatMessage({ id: 'status' }),
accessor: (r) => {
return r.status ? (
<Tag minimal={true}>
<T id={'published'} />
</Tag>
<Tag minimal={true}><T id={'published'} /></Tag>
) : (
<Tag minimal={true} intent={Intent.WARNING}>
<T id={'draft'} />
</Tag>
<Tag minimal={true} intent={Intent.WARNING}><T id={'draft'} /></Tag>
);
},
disableResizing: true,
@@ -227,7 +205,7 @@ function ManualJournalsDataTable({
content={actionMenuList(cell.row.original)}
position={Position.RIGHT_BOTTOM}
>
<Button icon={<Icon icon='more-h-16' iconSize={16} />} />
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
</Popover>
),
className: 'actions',
@@ -257,26 +235,41 @@ function ManualJournalsDataTable({
<LoadingIndicator loading={loading} mount={false}>
<DataTable
columns={columns}
data={manualJournals}
data={manualJournalsCurrentPage}
onFetchData={handleDataTableFetchData}
manualSortBy={true}
selectionColumn={true}
noInitialFetch={true}
sticky={true}
loading={manualJournalsLoading && !initialMount}
loading={manualJournalsLoading && !manualJournalsCurrentPage.length > 0}
onSelectedRowsChange={handleSelectedRowsChange}
pagination={true}
pagesCount={manualJournalsPagination.pagesCount}
initialPageSize={manualJournalsTableQuery.page_size}
initialPageIndex={manualJournalsTableQuery.page - 1}
/>
</LoadingIndicator>
);
}
export default compose(
withRouter,
withDialogActions,
withDashboardActions,
withManualJournalsActions,
withManualJournals(({ manualJournals, manualJournalsLoading }) => ({
manualJournals,
manualJournalsLoading,
})),
withManualJournals(
({
manualJournalsCurrentPage,
manualJournalsLoading,
manualJournalsPagination,
manualJournalsTableQuery,
}) => ({
manualJournalsCurrentPage,
manualJournalsLoading,
manualJournalsPagination,
manualJournalsTableQuery,
}),
),
withViewDetails,
)(ManualJournalsDataTable);

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useState, useMemo, useCallback } from 'react';
import { Route, Switch, useHistory } from 'react-router-dom';
import { Route, Switch, useHistory, withRouter } from 'react-router-dom';
import { useQuery } from 'react-query';
import { Alert, Intent } from '@blueprintjs/core';
import AppToaster from 'components/AppToaster';
@@ -13,8 +13,10 @@ import ManualJournalsDataTable from 'containers/Accounting/ManualJournalsDataTab
import ManualJournalsActionsBar from 'containers/Accounting/ManualJournalActionsBar';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withManualJournals from 'containers/Accounting/withManualJournals';
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
import withViewsActions from 'containers/Views/withViewsActions';
import withRouteActions from 'containers/Router/withRouteActions';
import { compose } from 'utils';
@@ -28,12 +30,17 @@ function ManualJournalsTable({
// #withViewsActions
requestFetchResourceViews,
// #withManualJournals
manualJournalsTableQuery,
// #withManualJournalsActions
requestFetchManualJournalsTable,
requestDeleteManualJournal,
requestPublishManualJournal,
requestDeleteBulkManualJournals,
addManualJournalsTableQueries,
addQuery,
}) {
const history = useHistory();
@@ -47,19 +54,21 @@ function ManualJournalsTable({
return requestFetchResourceViews('manual_journals');
});
const fetchManualJournals = useQuery('manual-journals-table',
() => requestFetchManualJournalsTable());
const fetchManualJournals = useQuery(
['manual-journals-table', manualJournalsTableQuery],
(key, q) => requestFetchManualJournalsTable(q),
);
useEffect(() => {
changePageTitle(formatMessage({id:'manual_journals'}));
}, [changePageTitle,formatMessage]);
changePageTitle(formatMessage({ id: 'manual_journals' }));
}, [changePageTitle, formatMessage]);
// Handle delete manual journal click.
const handleDeleteJournal = useCallback(
(journal) => {
setDeleteManualJournal(journal);
},
[setDeleteManualJournal]
[setDeleteManualJournal],
);
// Handle cancel delete manual journal.
@@ -71,28 +80,26 @@ function ManualJournalsTable({
const handleConfirmManualJournalDelete = useCallback(() => {
requestDeleteManualJournal(deleteManualJournal.id).then(() => {
AppToaster.show({
message: formatMessage({
id: 'the_journal_has_been_successfully_deleted',
}, {
number: deleteManualJournal.journal_number,
}),
message: formatMessage(
{ id: 'the_journal_has_been_successfully_deleted' },
{ number: deleteManualJournal.journal_number },
),
intent: Intent.SUCCESS,
});
setDeleteManualJournal(false);
});
}, [deleteManualJournal, requestDeleteManualJournal,formatMessage]);
}, [deleteManualJournal, requestDeleteManualJournal, formatMessage]);
// Calculates the selected rows count.
const selectedRowsCount = useMemo(
() => Object.values(selectedRows).length,
[selectedRows]);
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
selectedRows,
]);
const handleBulkDelete = useCallback(
(accountsIds) => {
setBulkDelete(accountsIds);
},
[setBulkDelete]
[setBulkDelete],
);
// Handle confirm journals bulk delete.
@@ -100,11 +107,10 @@ function ManualJournalsTable({
requestDeleteBulkManualJournals(bulkDelete)
.then(() => {
AppToaster.show({
message: formatMessage({
id: 'the_journals_has_been_successfully_deleted',
}, {
count: selectedRowsCount,
}),
message: formatMessage(
{ id: 'the_journals_has_been_successfully_deleted', },
{ count: selectedRowsCount, },
),
intent: Intent.SUCCESS,
});
setBulkDelete(false);
@@ -112,7 +118,12 @@ function ManualJournalsTable({
.catch((error) => {
setBulkDelete(false);
});
}, [requestDeleteBulkManualJournals, bulkDelete,formatMessage,selectedRowsCount]);
}, [
requestDeleteBulkManualJournals,
bulkDelete,
formatMessage,
selectedRowsCount,
]);
// Handle cancel bulk delete alert.
const handleCancelBulkDelete = useCallback(() => {
@@ -123,38 +134,49 @@ function ManualJournalsTable({
(journal) => {
history.push(`/manual-journals/${journal.id}/edit`);
},
[history]
[history],
);
// Handle filter change to re-fetch data-table.
const handleFilterChanged = useCallback(() => {
}, [fetchManualJournals]);
const handleFilterChanged = useCallback(() => {}, [fetchManualJournals]);
// Handle view change to re-fetch data table.
// const handleViewChanged = useCallback(() => {
// }, [fetchManualJournals]);
// Handle fetch data of manual jouranls datatable.
const handleFetchData = useCallback(({ pageIndex, pageSize, sortBy }) => {
addManualJournalsTableQueries({
...(sortBy.length > 0) ? {
column_sort_by: sortBy[0].id,
sort_order: sortBy[0].desc ? 'desc' : 'asc',
} : {},
});
}, [addManualJournalsTableQueries]);
const handleFetchData = useCallback(
({ pageIndex, pageSize, sortBy }) => {
const page = pageIndex + 1;
// addQuery('page_size', pageSize);
// addQuery('page', page);
addManualJournalsTableQueries({
...(sortBy.length > 0
? {
column_sort_by: sortBy[0].id,
sort_order: sortBy[0].desc ? 'desc' : 'asc',
}
: {}),
page_size: pageSize,
page,
});
},
[addManualJournalsTableQueries],
);
const handlePublishJournal = useCallback(
(journal) => {
requestPublishManualJournal(journal.id).then(() => {
AppToaster.show({
message: formatMessage({id:'the_manual_journal_id_has_been_published'})
message: formatMessage({
id: 'the_manual_journal_id_has_been_published',
}),
});
});
},
[requestPublishManualJournal,formatMessage]
[requestPublishManualJournal, formatMessage],
);
// Handle selected rows change.
@@ -162,12 +184,12 @@ function ManualJournalsTable({
(accounts) => {
setSelectedRows(accounts);
},
[setSelectedRows]
[setSelectedRows],
);
return (
<DashboardInsider
loading={fetchViews.isFetching || fetchManualJournals.isFetching}
loading={fetchViews.isFetching}
name={'manual-journals'}
>
<ManualJournalsActionsBar
@@ -183,7 +205,8 @@ function ManualJournalsTable({
path={[
'/manual-journals/:custom_view_id/custom_view',
'/manual-journals',
]}>
]}
>
<ManualJournalsViewTabs />
<ManualJournalsDataTable
@@ -199,25 +222,37 @@ function ManualJournalsTable({
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'delete'} />}
icon='trash'
icon="trash"
intent={Intent.DANGER}
isOpen={deleteManualJournal}
onCancel={handleCancelManualJournalDelete}
onConfirm={handleConfirmManualJournalDelete}
>
<p><T id={'once_delete_this_journal_category_you_will_able_to_restore_it'} /></p>
<p>
<T
id={
'once_delete_this_journal_category_you_will_able_to_restore_it'
}
/>
</p>
</Alert>
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'delete_count'} values={{ count: selectedRowsCount }} />}
icon='trash'
confirmButtonText={
<T id={'delete_count'} values={{ count: selectedRowsCount }} />
}
icon="trash"
intent={Intent.DANGER}
isOpen={bulkDelete}
onCancel={handleCancelBulkDelete}
onConfirm={handleConfirmBulkDelete}
>
<p><T id={'once_delete_these_journalss_you_will_not_able_restore_them'} /></p>
<p>
<T
id={'once_delete_these_journalss_you_will_not_able_restore_them'}
/>
</p>
</Alert>
</DashboardPageContent>
</DashboardInsider>
@@ -225,7 +260,12 @@ function ManualJournalsTable({
}
export default compose(
withRouter,
withRouteActions,
withDashboardActions,
withManualJournalsActions,
withViewsActions
withViewsActions,
withManualJournals(({ manualJournalsTableQuery }) => ({
manualJournalsTableQuery,
})),
)(ManualJournalsTable);

View File

@@ -1,20 +1,41 @@
import { connect } from 'react-redux';
import { pick, mapValues } from 'lodash';
import { getResourceViews } from 'store/customViews/customViews.selectors';
import {
getManualJournalsItems,
} from 'store/manualJournals/manualJournals.selectors'
import { getManualJournalsItems } from 'store/manualJournals/manualJournals.selectors';
const queryParamsKeys = ['page_size', 'page'];
export default (mapState) => {
const mapStateToProps = (state, props) => {
const queryParams = props.location
? new URLSearchParams(props.location.search)
: null;
const manualJournalsTableQuery = {
...state.manualJournals.tableQuery,
...(queryParams
? mapValues(
pick(Object.fromEntries(queryParams), queryParamsKeys),
(v) => parseInt(v, 10),
)
: {}),
};
const mapped = {
manualJournals: getManualJournalsItems(state, state.manualJournals.currentViewId),
manualJournalsCurrentPage: getManualJournalsItems(
state,
state.manualJournals.currentViewId,
manualJournalsTableQuery.page,
),
manualJournalsTableQuery,
manualJournalsViews: getResourceViews(state, 'manual_journals'),
manualJournalsItems: state.manualJournals.items,
manualJournalsTableQuery: state.manualJournals.tableQuery,
manualJournalsPagination: state.manualJournals.paginationMeta,
manualJournalsLoading: state.manualJournals.loading,
};
return mapState ? mapState(mapped, state, props) : mapped;
};
return connect(mapStateToProps);
};

View File

@@ -10,11 +10,10 @@ import {
const mapActionsToProps = (dispatch) => ({
requestDeleteManualJournal: (id) => dispatch(deleteManualJournal({ id })),
requestFetchManualJournalsTable: (query = {}) => dispatch(fetchManualJournalsTable({ query: { ...query } })),
requestFetchManualJournalsTable: (query = {}) => dispatch(fetchManualJournalsTable({ query })),
requestFetchManualJournal: (id) => dispatch(fetchManualJournal({ id })),
requestPublishManualJournal: (id) => dispatch(publishManualJournal({ id })),
requestDeleteBulkManualJournals: (ids) => dispatch(deleteBulkManualJournals({ ids })),
changeCurrentView: (id) => dispatch({
type: t.MANUAL_JOURNALS_SET_CURRENT_VIEW,
currentViewId: parseInt(id, 10),

View File

@@ -0,0 +1,31 @@
import { connect } from 'react-redux';
const mapDispatchToProps = (dispatch, props) => {
return {
addQuery: (key, value) => {
let pathname = props.location.pathname;
let searchParams = new URLSearchParams(props.location.search);
searchParams.set(key, value);
props.history.push({
pathname: pathname,
search: searchParams.toString(),
});
},
removeQuery: (key) => {
let pathname = props.location.pathname;
let searchParams = new URLSearchParams(props.location.search);
// returns the existing query string: '?type=fiction&author=fahid'
searchParams.delete(key);
props.history.push({
pathname: pathname,
search: searchParams.toString(),
});
},
}
}
export default connect(null, mapDispatchToProps)