mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
feat: Pagination component.
This commit is contained in:
@@ -16,7 +16,7 @@ import { ScrollSync, ScrollSyncPane } from 'react-scroll-sync';
|
|||||||
|
|
||||||
import { ConditionalWrapper } from 'utils';
|
import { ConditionalWrapper } from 'utils';
|
||||||
import { useUpdateEffect } from 'hooks';
|
import { useUpdateEffect } from 'hooks';
|
||||||
import { If } from 'components';
|
import { If, Pagination } from 'components';
|
||||||
|
|
||||||
const IndeterminateCheckbox = React.forwardRef(
|
const IndeterminateCheckbox = React.forwardRef(
|
||||||
({ indeterminate, ...rest }, ref) => {
|
({ indeterminate, ...rest }, ref) => {
|
||||||
@@ -46,6 +46,11 @@ export default function DataTable({
|
|||||||
expandToggleColumn = 2,
|
expandToggleColumn = 2,
|
||||||
noInitialFetch = false,
|
noInitialFetch = false,
|
||||||
spinnerProps = { size: 40 },
|
spinnerProps = { size: 40 },
|
||||||
|
|
||||||
|
pagination = false,
|
||||||
|
pagesCount: controlledPageCount,
|
||||||
|
initialPageIndex,
|
||||||
|
initialPageSize,
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
getTableProps,
|
getTableProps,
|
||||||
@@ -59,18 +64,28 @@ export default function DataTable({
|
|||||||
isAllRowsExpanded,
|
isAllRowsExpanded,
|
||||||
totalColumnsWidth,
|
totalColumnsWidth,
|
||||||
|
|
||||||
|
// page,
|
||||||
|
pageCount,
|
||||||
|
canPreviousPage,
|
||||||
|
canNextPage,
|
||||||
|
gotoPage,
|
||||||
|
previousPage,
|
||||||
|
nextPage,
|
||||||
|
setPageSize,
|
||||||
|
|
||||||
// Get the state from the instance
|
// Get the state from the instance
|
||||||
state: { pageIndex, pageSize, sortBy, selectedRowIds },
|
state: { pageIndex, pageSize, sortBy, selectedRowIds },
|
||||||
} = useTable(
|
} = useTable(
|
||||||
{
|
{
|
||||||
columns,
|
columns,
|
||||||
data: data,
|
data: data,
|
||||||
initialState: { pageIndex: 0, expanded }, // Pass our hoisted table state
|
initialState: {
|
||||||
manualPagination: true, // Tell the usePagination
|
pageIndex: initialPageIndex,
|
||||||
// hook that we'll handle our own data fetching
|
pageSize: initialPageSize,
|
||||||
// This means we'll also have to provide our own
|
expanded,
|
||||||
// pageCount.
|
}, // Pass our hoisted table state
|
||||||
// pageCount: controlledPageCount,
|
manualPagination: true,
|
||||||
|
pageCount: controlledPageCount,
|
||||||
getSubRows: (row) => row.children,
|
getSubRows: (row) => row.children,
|
||||||
manualSortBy,
|
manualSortBy,
|
||||||
expandSubRows,
|
expandSubRows,
|
||||||
@@ -80,10 +95,10 @@ export default function DataTable({
|
|||||||
useSortBy,
|
useSortBy,
|
||||||
useExpanded,
|
useExpanded,
|
||||||
useRowSelect,
|
useRowSelect,
|
||||||
usePagination,
|
|
||||||
useResizeColumns,
|
useResizeColumns,
|
||||||
useFlexLayout,
|
useFlexLayout,
|
||||||
useSticky,
|
useSticky,
|
||||||
|
usePagination,
|
||||||
(hooks) => {
|
(hooks) => {
|
||||||
hooks.visibleColumns.push((columns) => [
|
hooks.visibleColumns.push((columns) => [
|
||||||
// Let's make a column for selection
|
// Let's make a column for selection
|
||||||
@@ -197,6 +212,7 @@ export default function DataTable({
|
|||||||
{...cell.getCellProps({
|
{...cell.getCellProps({
|
||||||
className: classnames(cell.column.className || '', 'td'),
|
className: classnames(cell.column.className || '', 'td'),
|
||||||
})}
|
})}
|
||||||
|
onContextMenu={handleRowContextMenu(cell, row)}
|
||||||
>
|
>
|
||||||
{RenderCell({ cell, row, index })}
|
{RenderCell({ cell, row, index })}
|
||||||
</div>
|
</div>
|
||||||
@@ -337,6 +353,21 @@ export default function DataTable({
|
|||||||
</ScrollSyncPane>
|
</ScrollSyncPane>
|
||||||
</div>
|
</div>
|
||||||
</ScrollSync>
|
</ScrollSync>
|
||||||
|
|
||||||
|
<If condition={pagination && pageCount}>
|
||||||
|
<Pagination
|
||||||
|
initialPage={pageIndex + 1}
|
||||||
|
total={pageSize * pageCount}
|
||||||
|
size={pageSize}
|
||||||
|
onPageChange={(currentPage) => {
|
||||||
|
gotoPage(currentPage - 1);
|
||||||
|
}}
|
||||||
|
onPageSizeChange={(pageSize, currentPage) => {
|
||||||
|
gotoPage(currentPage - 1);
|
||||||
|
setPageSize(pageSize);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</If>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
218
client/src/components/Pagination.js
Normal file
218
client/src/components/Pagination.js
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
import React, { useReducer, useEffect } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Button, ButtonGroup, Intent, HTMLSelect, } from '@blueprintjs/core';
|
||||||
|
import { FormattedMessage as T } from 'react-intl';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { range } from 'lodash';
|
||||||
|
import { Icon } from 'components';
|
||||||
|
|
||||||
|
const getState = ({ currentPage, size, total }) => {
|
||||||
|
const totalPages = Math.ceil(total / size);
|
||||||
|
const visibleItems = 5;
|
||||||
|
const halfVisibleItems = Math.ceil(visibleItems / 2);
|
||||||
|
|
||||||
|
// create an array of pages to ng-repeat in the pager control
|
||||||
|
let startPage, endPage;
|
||||||
|
if (totalPages <= visibleItems) {
|
||||||
|
// less than {visibleItems} total pages so show
|
||||||
|
startPage = 1;
|
||||||
|
endPage = totalPages;
|
||||||
|
} else {
|
||||||
|
// more than {visibleItems} total pages so calculate start and end pages
|
||||||
|
if (currentPage <= halfVisibleItems) {
|
||||||
|
startPage = 1;
|
||||||
|
endPage = visibleItems;
|
||||||
|
} else if (currentPage + (halfVisibleItems - 1) >= totalPages) {
|
||||||
|
startPage = totalPages - (visibleItems - 1);
|
||||||
|
endPage = totalPages;
|
||||||
|
} else {
|
||||||
|
startPage = currentPage - halfVisibleItems;
|
||||||
|
endPage = currentPage + halfVisibleItems - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const pages = [...Array(endPage + 1 - startPage).keys()].map(
|
||||||
|
(i) => startPage + i,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Too large or small currentPage
|
||||||
|
let correctCurrentpage = currentPage;
|
||||||
|
if (currentPage > totalPages) correctCurrentpage = totalPages;
|
||||||
|
if (currentPage <= 0) correctCurrentpage = 1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentPage: correctCurrentpage,
|
||||||
|
size,
|
||||||
|
total,
|
||||||
|
pages,
|
||||||
|
totalPages,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const TYPE = {
|
||||||
|
PAGE_CHANGE: 'PAGE_CHANGE',
|
||||||
|
PAGE_SIZE_CHANGE: 'PAGE_SIZE_CHANGE',
|
||||||
|
INITIALIZE: 'INITIALIZE',
|
||||||
|
};
|
||||||
|
const reducer = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case TYPE.PAGE_CHANGE:
|
||||||
|
return getState({
|
||||||
|
currentPage: action.page,
|
||||||
|
size: state.size,
|
||||||
|
total: state.total,
|
||||||
|
});
|
||||||
|
case TYPE.PAGE_SIZE_CHANGE:
|
||||||
|
return getState({
|
||||||
|
currentPage: state.currentPage,
|
||||||
|
size: action.size,
|
||||||
|
total: state.total,
|
||||||
|
});
|
||||||
|
case TYPE.INITIALIZE:
|
||||||
|
return getState({
|
||||||
|
currentPage: state.currentPage,
|
||||||
|
size: action.size,
|
||||||
|
total: action.total,
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Pagination = ({
|
||||||
|
initialPage,
|
||||||
|
total,
|
||||||
|
size,
|
||||||
|
pageSizesOptions = [5, 12, 20, 30, 50, 75, 100, 150],
|
||||||
|
onPageChange,
|
||||||
|
onPageSizeChange,
|
||||||
|
}) => {
|
||||||
|
const [state, dispatch] = useReducer(
|
||||||
|
reducer,
|
||||||
|
{ currentPage: initialPage, total, size },
|
||||||
|
getState,
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch({
|
||||||
|
type: 'INITIALIZE',
|
||||||
|
total,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
}, [total, size]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="pagination">
|
||||||
|
<div class="pagination__buttons-group">
|
||||||
|
<ButtonGroup>
|
||||||
|
<Button
|
||||||
|
disabled={state.currentPage === 1}
|
||||||
|
onClick={() => {
|
||||||
|
dispatch({ type: 'PAGE_CHANGE', page: state.currentPage - 1 });
|
||||||
|
onPageChange(state.currentPage - 1);
|
||||||
|
}}
|
||||||
|
minimal={true}
|
||||||
|
className={'pagination__item pagination__item--previous'}
|
||||||
|
icon={<Icon icon={'arrow-back-24'} iconSize={12} />}
|
||||||
|
>
|
||||||
|
<T id='previous' />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{state.pages.map((page) => (
|
||||||
|
<Button
|
||||||
|
key={page}
|
||||||
|
intent={state.currentPage === page ? Intent.PRIMARY : Intent.NONE}
|
||||||
|
disabled={state.currentPage === page}
|
||||||
|
onClick={() => {
|
||||||
|
dispatch({ type: 'PAGE_CHANGE', page });
|
||||||
|
onPageChange(page);
|
||||||
|
}}
|
||||||
|
minimal={true}
|
||||||
|
className={classNames(
|
||||||
|
'pagination__item',
|
||||||
|
'pagination__item--page',
|
||||||
|
{
|
||||||
|
'is-active': state.currentPage === page,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{ page }
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
<Button
|
||||||
|
disabled={state.currentPage === state.totalPages}
|
||||||
|
onClick={() => {
|
||||||
|
dispatch({
|
||||||
|
type: 'PAGE_CHANGE',
|
||||||
|
page: state.currentPage + 1
|
||||||
|
});
|
||||||
|
onPageChange(state.currentPage + 1);
|
||||||
|
}}
|
||||||
|
minimal={true}
|
||||||
|
className={'pagination__item pagination__item--next'}
|
||||||
|
icon={<Icon icon={'arrow-forward-24'} iconSize={12} />}
|
||||||
|
>
|
||||||
|
<T id='next' />
|
||||||
|
</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pagination__controls">
|
||||||
|
<div class="pagination__goto-control">
|
||||||
|
Go to
|
||||||
|
<HTMLSelect
|
||||||
|
minimal={true}
|
||||||
|
options={range(1, state.totalPages + 1)}
|
||||||
|
value={state.currentPage}
|
||||||
|
onChange={(event) => {
|
||||||
|
const page = parseInt(event.currentTarget.value, 10);
|
||||||
|
|
||||||
|
dispatch({ type: 'PAGE_CHANGE', page });
|
||||||
|
onPageChange(page);
|
||||||
|
}}
|
||||||
|
minimal={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pagination__pagesize-control">
|
||||||
|
Page size
|
||||||
|
<HTMLSelect
|
||||||
|
minimal={true}
|
||||||
|
options={pageSizesOptions}
|
||||||
|
value={size}
|
||||||
|
onChange={(event) => {
|
||||||
|
const pageSize = parseInt(event.currentTarget.value, 10);
|
||||||
|
dispatch({ type: 'PAGE_SIZE_CHANGE', size: pageSize });
|
||||||
|
dispatch({ type: 'PAGE_CHANGE', page: 1 });
|
||||||
|
|
||||||
|
onPageSizeChange(pageSize, 1);
|
||||||
|
}}
|
||||||
|
minimal={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pagination__info">
|
||||||
|
<T id={'showing_current_page_to_total'} values={{
|
||||||
|
currentPage: state.currentPage,
|
||||||
|
totalPages: state.totalPages,
|
||||||
|
total: total,
|
||||||
|
}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Pagination.propTypes = {
|
||||||
|
initialPage: PropTypes.number.isRequired,
|
||||||
|
size: PropTypes.number.isRequired,
|
||||||
|
total: PropTypes.number.isRequired,
|
||||||
|
onPageChange: PropTypes.func,
|
||||||
|
onPageSizeChange: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
Pagination.defaultProps = {
|
||||||
|
initialPage: 1,
|
||||||
|
size: 25,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Pagination;
|
||||||
@@ -10,6 +10,7 @@ import ErrorMessage from './ErrorMessage';
|
|||||||
import MODIFIER from './modifiers';
|
import MODIFIER from './modifiers';
|
||||||
import FieldHint from './FieldHint';
|
import FieldHint from './FieldHint';
|
||||||
import MenuItemLabel from './MenuItemLabel';
|
import MenuItemLabel from './MenuItemLabel';
|
||||||
|
import Pagination from './Pagination';
|
||||||
|
|
||||||
const Hint = FieldHint;
|
const Hint = FieldHint;
|
||||||
|
|
||||||
@@ -27,5 +28,6 @@ export {
|
|||||||
FieldHint,
|
FieldHint,
|
||||||
Hint,
|
Hint,
|
||||||
MenuItemLabel,
|
MenuItemLabel,
|
||||||
|
Pagination,
|
||||||
// For,
|
// For,
|
||||||
};
|
};
|
||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
Position,
|
Position,
|
||||||
Tag,
|
Tag,
|
||||||
} from '@blueprintjs/core';
|
} 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 { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
@@ -29,18 +29,21 @@ import withViewDetails from 'containers/Views/withViewDetails';
|
|||||||
import withManualJournals from 'containers/Accounting/withManualJournals';
|
import withManualJournals from 'containers/Accounting/withManualJournals';
|
||||||
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
|
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
|
||||||
|
|
||||||
|
|
||||||
function ManualJournalsDataTable({
|
function ManualJournalsDataTable({
|
||||||
loading,
|
loading,
|
||||||
|
|
||||||
manualJournals,
|
// #withManualJournals
|
||||||
|
manualJournalsCurrentPage,
|
||||||
manualJournalsLoading,
|
manualJournalsLoading,
|
||||||
|
manualJournalsPagination,
|
||||||
|
manualJournalsTableQuery,
|
||||||
|
|
||||||
// #withDashboardActions
|
// #withDashboardActions
|
||||||
changeCurrentView,
|
changeCurrentView,
|
||||||
changePageSubtitle,
|
changePageSubtitle,
|
||||||
setTopbarEditView,
|
setTopbarEditView,
|
||||||
|
|
||||||
|
// #withViewDetails
|
||||||
viewId,
|
viewId,
|
||||||
viewMeta,
|
viewMeta,
|
||||||
|
|
||||||
@@ -96,27 +99,6 @@ function ManualJournalsDataTable({
|
|||||||
[onDeleteJournal],
|
[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(
|
const actionMenuList = useCallback(
|
||||||
(journal) => (
|
(journal) => (
|
||||||
<Menu>
|
<Menu>
|
||||||
@@ -171,13 +153,9 @@ function ManualJournalsDataTable({
|
|||||||
Header: formatMessage({ id: 'status' }),
|
Header: formatMessage({ id: 'status' }),
|
||||||
accessor: (r) => {
|
accessor: (r) => {
|
||||||
return r.status ? (
|
return r.status ? (
|
||||||
<Tag minimal={true}>
|
<Tag minimal={true}><T id={'published'} /></Tag>
|
||||||
<T id={'published'} />
|
|
||||||
</Tag>
|
|
||||||
) : (
|
) : (
|
||||||
<Tag minimal={true} intent={Intent.WARNING}>
|
<Tag minimal={true} intent={Intent.WARNING}><T id={'draft'} /></Tag>
|
||||||
<T id={'draft'} />
|
|
||||||
</Tag>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
disableResizing: true,
|
disableResizing: true,
|
||||||
@@ -227,7 +205,7 @@ function ManualJournalsDataTable({
|
|||||||
content={actionMenuList(cell.row.original)}
|
content={actionMenuList(cell.row.original)}
|
||||||
position={Position.RIGHT_BOTTOM}
|
position={Position.RIGHT_BOTTOM}
|
||||||
>
|
>
|
||||||
<Button icon={<Icon icon='more-h-16' iconSize={16} />} />
|
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
||||||
</Popover>
|
</Popover>
|
||||||
),
|
),
|
||||||
className: 'actions',
|
className: 'actions',
|
||||||
@@ -257,26 +235,41 @@ function ManualJournalsDataTable({
|
|||||||
<LoadingIndicator loading={loading} mount={false}>
|
<LoadingIndicator loading={loading} mount={false}>
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={manualJournals}
|
data={manualJournalsCurrentPage}
|
||||||
onFetchData={handleDataTableFetchData}
|
onFetchData={handleDataTableFetchData}
|
||||||
manualSortBy={true}
|
manualSortBy={true}
|
||||||
selectionColumn={true}
|
selectionColumn={true}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
sticky={true}
|
sticky={true}
|
||||||
loading={manualJournalsLoading && !initialMount}
|
loading={manualJournalsLoading && !manualJournalsCurrentPage.length > 0}
|
||||||
onSelectedRowsChange={handleSelectedRowsChange}
|
onSelectedRowsChange={handleSelectedRowsChange}
|
||||||
|
pagination={true}
|
||||||
|
|
||||||
|
pagesCount={manualJournalsPagination.pagesCount}
|
||||||
|
initialPageSize={manualJournalsTableQuery.page_size}
|
||||||
|
initialPageIndex={manualJournalsTableQuery.page - 1}
|
||||||
/>
|
/>
|
||||||
</LoadingIndicator>
|
</LoadingIndicator>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
|
withRouter,
|
||||||
withDialogActions,
|
withDialogActions,
|
||||||
withDashboardActions,
|
withDashboardActions,
|
||||||
withManualJournalsActions,
|
withManualJournalsActions,
|
||||||
withManualJournals(({ manualJournals, manualJournalsLoading }) => ({
|
withManualJournals(
|
||||||
manualJournals,
|
({
|
||||||
manualJournalsLoading,
|
manualJournalsCurrentPage,
|
||||||
})),
|
manualJournalsLoading,
|
||||||
|
manualJournalsPagination,
|
||||||
|
manualJournalsTableQuery,
|
||||||
|
}) => ({
|
||||||
|
manualJournalsCurrentPage,
|
||||||
|
manualJournalsLoading,
|
||||||
|
manualJournalsPagination,
|
||||||
|
manualJournalsTableQuery,
|
||||||
|
}),
|
||||||
|
),
|
||||||
withViewDetails,
|
withViewDetails,
|
||||||
)(ManualJournalsDataTable);
|
)(ManualJournalsDataTable);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
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 { useQuery } from 'react-query';
|
||||||
import { Alert, Intent } from '@blueprintjs/core';
|
import { Alert, Intent } from '@blueprintjs/core';
|
||||||
import AppToaster from 'components/AppToaster';
|
import AppToaster from 'components/AppToaster';
|
||||||
@@ -13,8 +13,10 @@ import ManualJournalsDataTable from 'containers/Accounting/ManualJournalsDataTab
|
|||||||
import ManualJournalsActionsBar from 'containers/Accounting/ManualJournalActionsBar';
|
import ManualJournalsActionsBar from 'containers/Accounting/ManualJournalActionsBar';
|
||||||
|
|
||||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||||
|
import withManualJournals from 'containers/Accounting/withManualJournals';
|
||||||
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
|
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
|
||||||
import withViewsActions from 'containers/Views/withViewsActions';
|
import withViewsActions from 'containers/Views/withViewsActions';
|
||||||
|
import withRouteActions from 'containers/Router/withRouteActions';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
@@ -28,12 +30,17 @@ function ManualJournalsTable({
|
|||||||
// #withViewsActions
|
// #withViewsActions
|
||||||
requestFetchResourceViews,
|
requestFetchResourceViews,
|
||||||
|
|
||||||
|
// #withManualJournals
|
||||||
|
manualJournalsTableQuery,
|
||||||
|
|
||||||
// #withManualJournalsActions
|
// #withManualJournalsActions
|
||||||
requestFetchManualJournalsTable,
|
requestFetchManualJournalsTable,
|
||||||
requestDeleteManualJournal,
|
requestDeleteManualJournal,
|
||||||
requestPublishManualJournal,
|
requestPublishManualJournal,
|
||||||
requestDeleteBulkManualJournals,
|
requestDeleteBulkManualJournals,
|
||||||
addManualJournalsTableQueries,
|
addManualJournalsTableQueries,
|
||||||
|
|
||||||
|
addQuery,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
@@ -47,19 +54,21 @@ function ManualJournalsTable({
|
|||||||
return requestFetchResourceViews('manual_journals');
|
return requestFetchResourceViews('manual_journals');
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchManualJournals = useQuery('manual-journals-table',
|
const fetchManualJournals = useQuery(
|
||||||
() => requestFetchManualJournalsTable());
|
['manual-journals-table', manualJournalsTableQuery],
|
||||||
|
(key, q) => requestFetchManualJournalsTable(q),
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
changePageTitle(formatMessage({id:'manual_journals'}));
|
changePageTitle(formatMessage({ id: 'manual_journals' }));
|
||||||
}, [changePageTitle,formatMessage]);
|
}, [changePageTitle, formatMessage]);
|
||||||
|
|
||||||
// Handle delete manual journal click.
|
// Handle delete manual journal click.
|
||||||
const handleDeleteJournal = useCallback(
|
const handleDeleteJournal = useCallback(
|
||||||
(journal) => {
|
(journal) => {
|
||||||
setDeleteManualJournal(journal);
|
setDeleteManualJournal(journal);
|
||||||
},
|
},
|
||||||
[setDeleteManualJournal]
|
[setDeleteManualJournal],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle cancel delete manual journal.
|
// Handle cancel delete manual journal.
|
||||||
@@ -71,28 +80,26 @@ function ManualJournalsTable({
|
|||||||
const handleConfirmManualJournalDelete = useCallback(() => {
|
const handleConfirmManualJournalDelete = useCallback(() => {
|
||||||
requestDeleteManualJournal(deleteManualJournal.id).then(() => {
|
requestDeleteManualJournal(deleteManualJournal.id).then(() => {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
message: formatMessage({
|
message: formatMessage(
|
||||||
id: 'the_journal_has_been_successfully_deleted',
|
{ id: 'the_journal_has_been_successfully_deleted' },
|
||||||
}, {
|
{ number: deleteManualJournal.journal_number },
|
||||||
number: deleteManualJournal.journal_number,
|
),
|
||||||
}),
|
|
||||||
intent: Intent.SUCCESS,
|
intent: Intent.SUCCESS,
|
||||||
});
|
});
|
||||||
setDeleteManualJournal(false);
|
setDeleteManualJournal(false);
|
||||||
});
|
});
|
||||||
}, [deleteManualJournal, requestDeleteManualJournal,formatMessage]);
|
}, [deleteManualJournal, requestDeleteManualJournal, formatMessage]);
|
||||||
|
|
||||||
|
|
||||||
// Calculates the selected rows count.
|
// Calculates the selected rows count.
|
||||||
const selectedRowsCount = useMemo(
|
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
|
||||||
() => Object.values(selectedRows).length,
|
selectedRows,
|
||||||
[selectedRows]);
|
]);
|
||||||
|
|
||||||
const handleBulkDelete = useCallback(
|
const handleBulkDelete = useCallback(
|
||||||
(accountsIds) => {
|
(accountsIds) => {
|
||||||
setBulkDelete(accountsIds);
|
setBulkDelete(accountsIds);
|
||||||
},
|
},
|
||||||
[setBulkDelete]
|
[setBulkDelete],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle confirm journals bulk delete.
|
// Handle confirm journals bulk delete.
|
||||||
@@ -100,11 +107,10 @@ function ManualJournalsTable({
|
|||||||
requestDeleteBulkManualJournals(bulkDelete)
|
requestDeleteBulkManualJournals(bulkDelete)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
message: formatMessage({
|
message: formatMessage(
|
||||||
id: 'the_journals_has_been_successfully_deleted',
|
{ id: 'the_journals_has_been_successfully_deleted', },
|
||||||
}, {
|
{ count: selectedRowsCount, },
|
||||||
count: selectedRowsCount,
|
),
|
||||||
}),
|
|
||||||
intent: Intent.SUCCESS,
|
intent: Intent.SUCCESS,
|
||||||
});
|
});
|
||||||
setBulkDelete(false);
|
setBulkDelete(false);
|
||||||
@@ -112,7 +118,12 @@ function ManualJournalsTable({
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setBulkDelete(false);
|
setBulkDelete(false);
|
||||||
});
|
});
|
||||||
}, [requestDeleteBulkManualJournals, bulkDelete,formatMessage,selectedRowsCount]);
|
}, [
|
||||||
|
requestDeleteBulkManualJournals,
|
||||||
|
bulkDelete,
|
||||||
|
formatMessage,
|
||||||
|
selectedRowsCount,
|
||||||
|
]);
|
||||||
|
|
||||||
// Handle cancel bulk delete alert.
|
// Handle cancel bulk delete alert.
|
||||||
const handleCancelBulkDelete = useCallback(() => {
|
const handleCancelBulkDelete = useCallback(() => {
|
||||||
@@ -123,13 +134,11 @@ function ManualJournalsTable({
|
|||||||
(journal) => {
|
(journal) => {
|
||||||
history.push(`/manual-journals/${journal.id}/edit`);
|
history.push(`/manual-journals/${journal.id}/edit`);
|
||||||
},
|
},
|
||||||
[history]
|
[history],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle filter change to re-fetch data-table.
|
// Handle filter change to re-fetch data-table.
|
||||||
const handleFilterChanged = useCallback(() => {
|
const handleFilterChanged = useCallback(() => {}, [fetchManualJournals]);
|
||||||
|
|
||||||
}, [fetchManualJournals]);
|
|
||||||
|
|
||||||
// Handle view change to re-fetch data table.
|
// Handle view change to re-fetch data table.
|
||||||
// const handleViewChanged = useCallback(() => {
|
// const handleViewChanged = useCallback(() => {
|
||||||
@@ -137,24 +146,37 @@ function ManualJournalsTable({
|
|||||||
// }, [fetchManualJournals]);
|
// }, [fetchManualJournals]);
|
||||||
|
|
||||||
// Handle fetch data of manual jouranls datatable.
|
// Handle fetch data of manual jouranls datatable.
|
||||||
const handleFetchData = useCallback(({ pageIndex, pageSize, sortBy }) => {
|
const handleFetchData = useCallback(
|
||||||
addManualJournalsTableQueries({
|
({ pageIndex, pageSize, sortBy }) => {
|
||||||
...(sortBy.length > 0) ? {
|
const page = pageIndex + 1;
|
||||||
column_sort_by: sortBy[0].id,
|
// addQuery('page_size', pageSize);
|
||||||
sort_order: sortBy[0].desc ? 'desc' : 'asc',
|
// addQuery('page', page);
|
||||||
} : {},
|
|
||||||
});
|
addManualJournalsTableQueries({
|
||||||
}, [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(
|
const handlePublishJournal = useCallback(
|
||||||
(journal) => {
|
(journal) => {
|
||||||
requestPublishManualJournal(journal.id).then(() => {
|
requestPublishManualJournal(journal.id).then(() => {
|
||||||
AppToaster.show({
|
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.
|
// Handle selected rows change.
|
||||||
@@ -162,12 +184,12 @@ function ManualJournalsTable({
|
|||||||
(accounts) => {
|
(accounts) => {
|
||||||
setSelectedRows(accounts);
|
setSelectedRows(accounts);
|
||||||
},
|
},
|
||||||
[setSelectedRows]
|
[setSelectedRows],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardInsider
|
<DashboardInsider
|
||||||
loading={fetchViews.isFetching || fetchManualJournals.isFetching}
|
loading={fetchViews.isFetching}
|
||||||
name={'manual-journals'}
|
name={'manual-journals'}
|
||||||
>
|
>
|
||||||
<ManualJournalsActionsBar
|
<ManualJournalsActionsBar
|
||||||
@@ -183,7 +205,8 @@ function ManualJournalsTable({
|
|||||||
path={[
|
path={[
|
||||||
'/manual-journals/:custom_view_id/custom_view',
|
'/manual-journals/:custom_view_id/custom_view',
|
||||||
'/manual-journals',
|
'/manual-journals',
|
||||||
]}>
|
]}
|
||||||
|
>
|
||||||
<ManualJournalsViewTabs />
|
<ManualJournalsViewTabs />
|
||||||
|
|
||||||
<ManualJournalsDataTable
|
<ManualJournalsDataTable
|
||||||
@@ -199,25 +222,37 @@ function ManualJournalsTable({
|
|||||||
<Alert
|
<Alert
|
||||||
cancelButtonText={<T id={'cancel'} />}
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
confirmButtonText={<T id={'delete'} />}
|
confirmButtonText={<T id={'delete'} />}
|
||||||
icon='trash'
|
icon="trash"
|
||||||
intent={Intent.DANGER}
|
intent={Intent.DANGER}
|
||||||
isOpen={deleteManualJournal}
|
isOpen={deleteManualJournal}
|
||||||
onCancel={handleCancelManualJournalDelete}
|
onCancel={handleCancelManualJournalDelete}
|
||||||
onConfirm={handleConfirmManualJournalDelete}
|
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>
|
||||||
|
|
||||||
<Alert
|
<Alert
|
||||||
cancelButtonText={<T id={'cancel'} />}
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
confirmButtonText={<T id={'delete_count'} values={{ count: selectedRowsCount }} />}
|
confirmButtonText={
|
||||||
icon='trash'
|
<T id={'delete_count'} values={{ count: selectedRowsCount }} />
|
||||||
|
}
|
||||||
|
icon="trash"
|
||||||
intent={Intent.DANGER}
|
intent={Intent.DANGER}
|
||||||
isOpen={bulkDelete}
|
isOpen={bulkDelete}
|
||||||
onCancel={handleCancelBulkDelete}
|
onCancel={handleCancelBulkDelete}
|
||||||
onConfirm={handleConfirmBulkDelete}
|
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>
|
</Alert>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</DashboardInsider>
|
</DashboardInsider>
|
||||||
@@ -225,7 +260,12 @@ function ManualJournalsTable({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
|
withRouter,
|
||||||
|
withRouteActions,
|
||||||
withDashboardActions,
|
withDashboardActions,
|
||||||
withManualJournalsActions,
|
withManualJournalsActions,
|
||||||
withViewsActions
|
withViewsActions,
|
||||||
|
withManualJournals(({ manualJournalsTableQuery }) => ({
|
||||||
|
manualJournalsTableQuery,
|
||||||
|
})),
|
||||||
)(ManualJournalsTable);
|
)(ManualJournalsTable);
|
||||||
|
|||||||
@@ -1,16 +1,37 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { pick, mapValues } from 'lodash';
|
||||||
import { getResourceViews } from 'store/customViews/customViews.selectors';
|
import { getResourceViews } from 'store/customViews/customViews.selectors';
|
||||||
import {
|
import { getManualJournalsItems } from 'store/manualJournals/manualJournals.selectors';
|
||||||
getManualJournalsItems,
|
|
||||||
} from 'store/manualJournals/manualJournals.selectors'
|
const queryParamsKeys = ['page_size', 'page'];
|
||||||
|
|
||||||
export default (mapState) => {
|
export default (mapState) => {
|
||||||
const mapStateToProps = (state, props) => {
|
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 = {
|
const mapped = {
|
||||||
manualJournals: getManualJournalsItems(state, state.manualJournals.currentViewId),
|
manualJournalsCurrentPage: getManualJournalsItems(
|
||||||
|
state,
|
||||||
|
state.manualJournals.currentViewId,
|
||||||
|
manualJournalsTableQuery.page,
|
||||||
|
),
|
||||||
|
manualJournalsTableQuery,
|
||||||
manualJournalsViews: getResourceViews(state, 'manual_journals'),
|
manualJournalsViews: getResourceViews(state, 'manual_journals'),
|
||||||
manualJournalsItems: state.manualJournals.items,
|
manualJournalsItems: state.manualJournals.items,
|
||||||
manualJournalsTableQuery: state.manualJournals.tableQuery,
|
|
||||||
|
manualJournalsPagination: state.manualJournals.paginationMeta,
|
||||||
manualJournalsLoading: state.manualJournals.loading,
|
manualJournalsLoading: state.manualJournals.loading,
|
||||||
};
|
};
|
||||||
return mapState ? mapState(mapped, state, props) : mapped;
|
return mapState ? mapState(mapped, state, props) : mapped;
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ import {
|
|||||||
|
|
||||||
const mapActionsToProps = (dispatch) => ({
|
const mapActionsToProps = (dispatch) => ({
|
||||||
requestDeleteManualJournal: (id) => dispatch(deleteManualJournal({ id })),
|
requestDeleteManualJournal: (id) => dispatch(deleteManualJournal({ id })),
|
||||||
requestFetchManualJournalsTable: (query = {}) => dispatch(fetchManualJournalsTable({ query: { ...query } })),
|
requestFetchManualJournalsTable: (query = {}) => dispatch(fetchManualJournalsTable({ query })),
|
||||||
requestFetchManualJournal: (id) => dispatch(fetchManualJournal({ id })),
|
requestFetchManualJournal: (id) => dispatch(fetchManualJournal({ id })),
|
||||||
requestPublishManualJournal: (id) => dispatch(publishManualJournal({ id })),
|
requestPublishManualJournal: (id) => dispatch(publishManualJournal({ id })),
|
||||||
requestDeleteBulkManualJournals: (ids) => dispatch(deleteBulkManualJournals({ ids })),
|
requestDeleteBulkManualJournals: (ids) => dispatch(deleteBulkManualJournals({ ids })),
|
||||||
|
|
||||||
changeCurrentView: (id) => dispatch({
|
changeCurrentView: (id) => dispatch({
|
||||||
type: t.MANUAL_JOURNALS_SET_CURRENT_VIEW,
|
type: t.MANUAL_JOURNALS_SET_CURRENT_VIEW,
|
||||||
currentViewId: parseInt(id, 10),
|
currentViewId: parseInt(id, 10),
|
||||||
|
|||||||
31
client/src/containers/Router/withRouteActions.js
Normal file
31
client/src/containers/Router/withRouteActions.js
Normal 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)
|
||||||
@@ -468,4 +468,7 @@ export default {
|
|||||||
remove_the_line: 'Remove the line',
|
remove_the_line: 'Remove the line',
|
||||||
no_results: 'No results',
|
no_results: 'No results',
|
||||||
all_reports: 'All Reports',
|
all_reports: 'All Reports',
|
||||||
|
next: 'Next',
|
||||||
|
previous: 'Previous',
|
||||||
|
showing_current_page_to_total: 'Showing {currentPage} to {totalPages} of {total} entries',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,6 +41,18 @@ export default {
|
|||||||
],
|
],
|
||||||
viewBox: '0 0 448 512',
|
viewBox: '0 0 448 512',
|
||||||
},
|
},
|
||||||
|
'arrow-back-24': {
|
||||||
|
path: [
|
||||||
|
'M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z',
|
||||||
|
],
|
||||||
|
viewBox: '0 0 24, 24',
|
||||||
|
},
|
||||||
|
'arrow-forward-24': {
|
||||||
|
path: [
|
||||||
|
'M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8-8-8z',
|
||||||
|
],
|
||||||
|
viewBox: '0 0 24 24',
|
||||||
|
},
|
||||||
'ellipsis-h': {
|
'ellipsis-h': {
|
||||||
path: [
|
path: [
|
||||||
'M304 256c0 26.5-21.5 48-48 48s-48-21.5-48-48 21.5-48 48-48 48 21.5 48 48zm120-48c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm-336 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z',
|
'M304 256c0 26.5-21.5 48-48 48s-48-21.5-48-48 21.5-48 48-48 48 21.5 48 48zm120-48c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm-336 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z',
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ const initialState = {
|
|||||||
views: {},
|
views: {},
|
||||||
accountsTypes: [],
|
accountsTypes: [],
|
||||||
accountsById: {},
|
accountsById: {},
|
||||||
tableQuery: {},
|
tableQuery: {
|
||||||
|
pageSize: 2,
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
currentViewId: -1,
|
currentViewId: -1,
|
||||||
selectedRows: [],
|
selectedRows: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -91,8 +94,3 @@ export default createTableQueryReducers('accounts', accountsReducer);
|
|||||||
export const getAccountById = (state, id) => {
|
export const getAccountById = (state, id) => {
|
||||||
return state.accounts.accountsById[id];
|
return state.accounts.accountsById[id];
|
||||||
};
|
};
|
||||||
|
|
||||||
// export default {
|
|
||||||
// // ...accountsReducer,
|
|
||||||
// // testReducer,
|
|
||||||
// }
|
|
||||||
@@ -2,44 +2,55 @@ import ApiService from 'services/ApiService';
|
|||||||
import t from 'store/types';
|
import t from 'store/types';
|
||||||
|
|
||||||
export const makeJournalEntries = ({ form }) => {
|
export const makeJournalEntries = ({ form }) => {
|
||||||
return (dispatch) => new Promise((resolve, reject) => {
|
return (dispatch) =>
|
||||||
ApiService.post('accounting/make-journal-entries', form).then((response) => {
|
new Promise((resolve, reject) => {
|
||||||
resolve(response);
|
ApiService.post('accounting/make-journal-entries', form)
|
||||||
}).catch((error) => {
|
.then((response) => {
|
||||||
const { response } = error;
|
resolve(response);
|
||||||
const { data } = response;
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
const { response } = error;
|
||||||
|
const { data } = response;
|
||||||
|
|
||||||
reject(data?.errors);
|
reject(data?.errors);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchManualJournal = ({ id }) => {
|
export const fetchManualJournal = ({ id }) => {
|
||||||
return (dispatch) => new Promise((resolve, reject) => {
|
return (dispatch) =>
|
||||||
ApiService.get(`accounting/manual-journals/${id}`).then((response) => {
|
new Promise((resolve, reject) => {
|
||||||
dispatch({
|
ApiService.get(`accounting/manual-journals/${id}`)
|
||||||
type: t.MANUAL_JOURNAL_SET,
|
.then((response) => {
|
||||||
payload: {
|
dispatch({
|
||||||
id,
|
type: t.MANUAL_JOURNAL_SET,
|
||||||
manualJournal: response.data.manual_journal,
|
payload: {
|
||||||
},
|
id,
|
||||||
});
|
manualJournal: response.data.manual_journal,
|
||||||
resolve(response);
|
},
|
||||||
}).catch((error) => { reject(error); });
|
});
|
||||||
});
|
resolve(response);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const editManualJournal = ({ form, id }) => {
|
export const editManualJournal = ({ form, id }) => {
|
||||||
return (dispatch) => new Promise((resolve, reject) => {
|
return (dispatch) =>
|
||||||
ApiService.post(`accounting/manual-journals/${id}`, form).then((response) => {
|
new Promise((resolve, reject) => {
|
||||||
resolve(response);
|
ApiService.post(`accounting/manual-journals/${id}`, form)
|
||||||
}).catch((error) => {
|
.then((response) => {
|
||||||
const { response } = error;
|
resolve(response);
|
||||||
const { data } = response;
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
const { response } = error;
|
||||||
|
const { data } = response;
|
||||||
|
|
||||||
reject(data?.errors);
|
reject(data?.errors);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteManualJournal = ({ id }) => {
|
export const deleteManualJournal = ({ id }) => {
|
||||||
@@ -53,24 +64,27 @@ export const deleteManualJournal = ({ id }) => {
|
|||||||
});
|
});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
})
|
})
|
||||||
.catch((error) => { reject(error); });
|
.catch((error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const deleteBulkManualJournals = ({ ids }) => {
|
export const deleteBulkManualJournals = ({ ids }) => {
|
||||||
return (dispatch) => new Promise((resolve, reject) => {
|
return (dispatch) =>
|
||||||
ApiService.delete('accounting/manual-journals', { params: { ids } })
|
new Promise((resolve, reject) => {
|
||||||
.then((response) => {
|
ApiService.delete('accounting/manual-journals', { params: { ids } })
|
||||||
dispatch({
|
.then((response) => {
|
||||||
type: t.MANUAL_JOURNALS_BULK_DELETE,
|
dispatch({
|
||||||
payload: { ids },
|
type: t.MANUAL_JOURNALS_BULK_DELETE,
|
||||||
|
payload: { ids },
|
||||||
|
});
|
||||||
|
resolve(response);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error.response.data.errors || []);
|
||||||
});
|
});
|
||||||
resolve(response);
|
});
|
||||||
}).catch((error) => {
|
|
||||||
reject(error.response.data.errors || []);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const publishManualJournal = ({ id }) => {
|
export const publishManualJournal = ({ id }) => {
|
||||||
@@ -84,40 +98,44 @@ export const publishManualJournal = ({ id }) => {
|
|||||||
});
|
});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
})
|
})
|
||||||
.catch((error) => { reject(error); });
|
.catch((error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export const fetchManualJournalsTable = ({ query } = {}) => {
|
export const fetchManualJournalsTable = ({ query } = {}) => {
|
||||||
return (dispatch, getState) =>
|
return (dispatch, getState) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
const pageQuery = getState().manualJournals.tableQuery;
|
|
||||||
dispatch({
|
|
||||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
|
||||||
});
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.MANUAL_JOURNALS_TABLE_LOADING,
|
type: t.MANUAL_JOURNALS_TABLE_LOADING,
|
||||||
loading: true,
|
loading: true,
|
||||||
});
|
});
|
||||||
ApiService.get('accounting/manual-journals', {
|
ApiService.get('accounting/manual-journals', {
|
||||||
params: { ...pageQuery, ...query },
|
params: { ...query },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.MANUAL_JOURNALS_PAGE_SET,
|
type: t.MANUAL_JOURNALS_PAGE_SET,
|
||||||
manual_journals: response.data.manualJournals.results,
|
payload: {
|
||||||
customViewId: response.data.customViewId || -1,
|
manualJournals: response.data.manualJournals.results,
|
||||||
|
customViewId: response.data.customViewId || -1,
|
||||||
|
pagination: response.data.manualJournals.pagination,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.MANUAL_JOURNALS_ITEMS_SET,
|
type: t.MANUAL_JOURNALS_ITEMS_SET,
|
||||||
manual_journals: response.data.manualJournals.results,
|
manual_journals: response.data.manualJournals.results,
|
||||||
});
|
});
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.MANUAL_JOURNALS_TABLE_LOADING,
|
type: 'MANUAL_JOURNALS_PAGINATION_SET',
|
||||||
loading: false,
|
payload: {
|
||||||
|
pagination: response.data.manualJournals.pagination,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
type: t.MANUAL_JOURNALS_TABLE_LOADING,
|
||||||
|
loading: false,
|
||||||
});
|
});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,7 +8,13 @@ const initialState = {
|
|||||||
views: {},
|
views: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
currentViewId: -1,
|
currentViewId: -1,
|
||||||
tableQuery: {},
|
tableQuery: {
|
||||||
|
page_size: 6,
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
|
paginationMeta: {
|
||||||
|
total: 0,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultJournal = {
|
const defaultJournal = {
|
||||||
@@ -45,12 +51,19 @@ const reducer = createReducer(initialState, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
[t.MANUAL_JOURNALS_PAGE_SET]: (state, action) => {
|
[t.MANUAL_JOURNALS_PAGE_SET]: (state, action) => {
|
||||||
const viewId = action.customViewId || -1;
|
const { customViewId, manualJournals, pagination } = action.payload;
|
||||||
|
|
||||||
|
const viewId = customViewId || -1;
|
||||||
const view = state.views[viewId] || {};
|
const view = state.views[viewId] || {};
|
||||||
|
|
||||||
state.views[viewId] = {
|
state.views[viewId] = {
|
||||||
...view,
|
...view,
|
||||||
ids: action.manual_journals.map((i) => i.id),
|
pages: {
|
||||||
|
...(state.views?.[viewId]?.pages || {}),
|
||||||
|
[pagination.page]: {
|
||||||
|
ids: (manualJournals.map((i) => i.id)),
|
||||||
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -78,6 +91,22 @@ const reducer = createReducer(initialState, {
|
|||||||
});
|
});
|
||||||
state.items = items;
|
state.items = items;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[t.MANUAL_JOURNALS_PAGINATION_SET]: (state, action) => {
|
||||||
|
const { pagination } = action.payload;
|
||||||
|
const mapped = {
|
||||||
|
pageSize: parseInt(pagination.pageSize, 10),
|
||||||
|
page: parseInt(pagination.page, 10),
|
||||||
|
total: parseInt(pagination.total, 10),
|
||||||
|
};
|
||||||
|
|
||||||
|
state.paginationMeta = {
|
||||||
|
...state.paginationMeta,
|
||||||
|
...mapped,
|
||||||
|
pagesCount: Math.ceil(mapped.total / mapped.pageSize),
|
||||||
|
pageIndex: Math.max(mapped.page - 1, 0),
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default createTableQueryReducers('manual_journals', reducer);
|
export default createTableQueryReducers('manual_journals', reducer);
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { pickItemsFromIds } from 'store/selectors';
|
import { pickItemsFromIds } from 'store/selectors';
|
||||||
|
|
||||||
export const getManualJournalsItems = (state, viewId) => {
|
export const getManualJournalsItems = (state, viewId, pageNumber) => {
|
||||||
const accountsView = state.manualJournals.views[viewId || -1];
|
const accountsViewPages = state.manualJournals.views[viewId || -1];
|
||||||
|
const accountsView = accountsViewPages?.pages?.[pageNumber]?.ids || {};
|
||||||
const accountsItems = state.manualJournals.items;
|
const accountsItems = state.manualJournals.items;
|
||||||
|
|
||||||
return typeof accountsView === 'object'
|
return typeof accountsView === 'object'
|
||||||
? pickItemsFromIds(accountsItems, accountsView.ids) || []
|
? pickItemsFromIds(accountsItems, accountsView) || []
|
||||||
: [];
|
: [];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ export default {
|
|||||||
|
|
||||||
MANUAL_JOURNAL_PUBLISH: 'MANUAL_JOURNAL_PUBLISH',
|
MANUAL_JOURNAL_PUBLISH: 'MANUAL_JOURNAL_PUBLISH',
|
||||||
MANUAL_JOURNALS_BULK_DELETE: 'MANUAL_JOURNALS_BULK_DELETE',
|
MANUAL_JOURNALS_BULK_DELETE: 'MANUAL_JOURNALS_BULK_DELETE',
|
||||||
|
MANUAL_JOURNALS_PAGINATION_SET: 'MANUAL_JOURNALS_PAGINATION_SET',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ $pt-font-family: Noto Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
|
|||||||
@import 'components/dialog';
|
@import 'components/dialog';
|
||||||
@import 'components/custom-scrollbar';
|
@import 'components/custom-scrollbar';
|
||||||
@import 'components/dragzone';
|
@import 'components/dragzone';
|
||||||
|
@import 'components/pagination';
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
@import 'pages/dashboard';
|
@import 'pages/dashboard';
|
||||||
|
|||||||
101
client/src/style/components/pagination.scss
Normal file
101
client/src/style/components/pagination.scss
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
.pagination{
|
||||||
|
display: flex;
|
||||||
|
padding: 25px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
.bp3-button{
|
||||||
|
background: transparent;
|
||||||
|
padding: 4px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item{
|
||||||
|
min-width: 24px;
|
||||||
|
min-height: 24px;
|
||||||
|
|
||||||
|
&:not([class*="bp3-intent-"]){
|
||||||
|
color: #666666;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
background-color: #E6EFFB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bp3-icon{
|
||||||
|
margin-right: 4px;
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination .pagination__buttons-group .bp3-button-group &{
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
&--next,
|
||||||
|
&--previous{
|
||||||
|
|
||||||
|
&.bp3-button{
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active{
|
||||||
|
&.bp3-intent-primary:disabled,
|
||||||
|
&.bp3-intent-primary.bp3-disabled{
|
||||||
|
background-color: #E6EFFB;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not([class*="bp3-intent-"]) {
|
||||||
|
}
|
||||||
|
.bp3-button-text{
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--next{
|
||||||
|
|
||||||
|
.bp3-icon{
|
||||||
|
order: 1;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info{
|
||||||
|
padding-top: 6px;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__controls{
|
||||||
|
display: flex;
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
.bp3-html-select{
|
||||||
|
margin-left: 6px;
|
||||||
|
|
||||||
|
select{
|
||||||
|
height: 20px;
|
||||||
|
width: auto;
|
||||||
|
padding: 0;
|
||||||
|
padding-right: 0px;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
font-size: 13px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #666;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__goto-control{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__pagesize-control{
|
||||||
|
margin-left: 12px;
|
||||||
|
padding-top: 4px;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,6 +72,8 @@ export default {
|
|||||||
*/
|
*/
|
||||||
manualJournals: {
|
manualJournals: {
|
||||||
validation: [
|
validation: [
|
||||||
|
query('page').optional().isNumeric().toInt(),
|
||||||
|
query('page_size').optional().isNumeric().toInt(),
|
||||||
query('custom_view_id').optional().isNumeric().toInt(),
|
query('custom_view_id').optional().isNumeric().toInt(),
|
||||||
query('stringified_filter_roles').optional().isJSON(),
|
query('stringified_filter_roles').optional().isJSON(),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user