mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
feat: fix items list datatable.
This commit is contained in:
@@ -1,20 +1,18 @@
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
FormattedHTMLMessage,
|
||||
useIntl,
|
||||
} from 'react-intl';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import { handleDeleteErrors } from 'containers/Items/utils';
|
||||
import { useDeleteItem } from 'hooks/query';
|
||||
|
||||
import {
|
||||
useDeleteItem
|
||||
} from 'hooks/query';
|
||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||
import withItemsActions from 'containers/Items/withItemsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -30,15 +28,19 @@ function ItemDeleteAlert({
|
||||
|
||||
// #withAlertActions
|
||||
closeAlert,
|
||||
|
||||
// #withItemsActions
|
||||
addItemsTableQueries
|
||||
}) {
|
||||
const { mutateAsync: deleteItem, isLoading } = useDeleteItem();
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
// handle cancel delete item alert.
|
||||
// Handle cancel delete item alert.
|
||||
const handleCancelItemDelete = () => {
|
||||
closeAlert(name);
|
||||
};
|
||||
|
||||
// Handle confirm delete item.
|
||||
const handleConfirmDeleteItem = () => {
|
||||
deleteItem(itemId)
|
||||
.then(() => {
|
||||
@@ -48,6 +50,8 @@ function ItemDeleteAlert({
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
// Reset to page number one.
|
||||
addItemsTableQueries({ page: 1 });
|
||||
})
|
||||
.catch(({ errors }) => {
|
||||
handleDeleteErrors(errors);
|
||||
@@ -80,4 +84,5 @@ function ItemDeleteAlert({
|
||||
export default compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
withItemsActions
|
||||
)(ItemDeleteAlert);
|
||||
|
||||
@@ -179,6 +179,7 @@ function InventoryAdjustmentDataTable({
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
isLoading={isLoading}
|
||||
noResults={'There is no inventory adjustments transactions yet.'}
|
||||
// pagesCount={inventoryAdjustmentsPagination.pagesCount}
|
||||
// initialPageSize={inventoryAdjustmentsPagination.pageSize}
|
||||
// initialPageIndex={inventoryAdjustmentsPagination.page - 1}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { ItemFormProvider } from './ItemFormProvider';
|
||||
@@ -12,8 +12,21 @@ import { compose } from 'utils';
|
||||
/**
|
||||
* Item form page.
|
||||
*/
|
||||
function ItemFormPage() {
|
||||
function ItemFormPage({
|
||||
// #withDashboardActions
|
||||
setDashboardBackLink
|
||||
}) {
|
||||
const { id } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
// Show the back link on dashboard topbar.
|
||||
setDashboardBackLink(true);
|
||||
|
||||
return () => {
|
||||
// Hide the back link on dashboard topbar.
|
||||
setDashboardBackLink(false);
|
||||
};
|
||||
}, [setDashboardBackLink]);
|
||||
|
||||
return (
|
||||
<ItemFormProvider itemId={id}>
|
||||
@@ -24,4 +37,6 @@ function ItemFormPage() {
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withDashboardActions)(ItemFormPage);
|
||||
export default compose(
|
||||
withDashboardActions,
|
||||
)(ItemFormPage);
|
||||
|
||||
@@ -53,7 +53,7 @@ function ItemsActionsBar({
|
||||
// Handle tab changing.
|
||||
const handleTabChange = (viewId) => {
|
||||
addItemsTableQueries({
|
||||
custom_view_id: viewId.id || null,
|
||||
customViewId: viewId.id || null,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -87,7 +87,7 @@ function ItemsActionsBar({
|
||||
>
|
||||
<Button
|
||||
className={classNames(Classes.MINIMAL, 'button--filter')}
|
||||
text={`${formatMessage({ id: 'filters_applied' })}`}
|
||||
text={`${formatMessage({ id: 'filter' })}`}
|
||||
icon={<Icon icon="filter-16" iconSize={16} />}
|
||||
/>
|
||||
</Popover>
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
CostPriceCell,
|
||||
ItemTypeAccessor,
|
||||
ItemsActionsTableCell,
|
||||
ItemsActionMenuList
|
||||
} from './components';
|
||||
|
||||
// Items datatable.
|
||||
@@ -118,11 +119,14 @@ function ItemsDataTable({
|
||||
manualSortBy={true}
|
||||
pagesCount={1}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
autoResetPage={true}
|
||||
manualPagination={true}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
initialPageSize={pagination.pageSize}
|
||||
initialPageIndex={pagination.page}
|
||||
|
||||
pageSize={pagination.pageSize}
|
||||
pageIndex={pagination.page - 1}
|
||||
ContextMenu={ItemsActionMenuList}
|
||||
{...tableProps}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
import React, { useEffect, createContext } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import { transformTableQueryToParams, isTableEmptyStatus } from 'utils';
|
||||
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import { useResourceViews, useResourceFields, useItems } from 'hooks/query';
|
||||
import { useDashboardPageTitle } from 'hooks/state';
|
||||
|
||||
const ItemsContext = createContext();
|
||||
|
||||
function ItemsListProvider({ query, ...props }) {
|
||||
/**
|
||||
* Items list provider.
|
||||
*/
|
||||
function ItemsListProvider({
|
||||
query,
|
||||
...props
|
||||
}) {
|
||||
// Fetch accounts resource views and fields.
|
||||
const { data: itemsViews, isFetching: isViewsLoading } = useResourceViews(
|
||||
'items',
|
||||
@@ -21,11 +29,16 @@ function ItemsListProvider({ query, ...props }) {
|
||||
// Handle fetching the items table based on the given query.
|
||||
const {
|
||||
data: { items, pagination, filterMeta },
|
||||
isFetching: isItemsLoading,
|
||||
} = useItems(query);
|
||||
isFetching: isItemsFetching,
|
||||
isLoading: isItemsLoading,
|
||||
} = useItems({
|
||||
...transformTableQueryToParams(query)
|
||||
}, { keepPreviousData: true });
|
||||
|
||||
// Detarmines the datatable empty status.
|
||||
const isEmptyStatus = isEmpty(items) && !isItemsLoading && !filterMeta.view;
|
||||
const isEmptyStatus = isTableEmptyStatus({
|
||||
data: items, pagination, filterMeta,
|
||||
}) && !isItemsFetching;
|
||||
|
||||
// Format message intl.
|
||||
const { formatMessage } = useIntl();
|
||||
@@ -42,15 +55,15 @@ function ItemsListProvider({ query, ...props }) {
|
||||
itemsFields,
|
||||
items,
|
||||
pagination,
|
||||
|
||||
isViewsLoading,
|
||||
isItemsLoading,
|
||||
isEmptyStatus: false,
|
||||
isItemsFetching: isItemsFetching,
|
||||
isEmptyStatus,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={isFieldsLoading || isViewsLoading}
|
||||
loading={isFieldsLoading}
|
||||
name={'items-list'}
|
||||
>
|
||||
<ItemsContext.Provider value={state} {...props} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Switch, Route, useHistory } from 'react-router-dom';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import ItemsViewsTabs from './ItemsViewsTabs';
|
||||
import ItemsDataTable from './ItemsDataTable';
|
||||
@@ -7,9 +7,39 @@ import ItemsDataTable from './ItemsDataTable';
|
||||
import withItemsActions from 'containers/Items/withItemsActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withItems from 'containers/Items/withItems';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import { useItemsListContext } from './ItemsListProvider';
|
||||
|
||||
function transformPaginationToProps(pagination) {
|
||||
const { page, pageSize, total } = pagination;
|
||||
|
||||
return {
|
||||
initialPageIndex: Math.max(page - 1, 0),
|
||||
initialPageSize: pageSize,
|
||||
pagesCount: Math.ceil(total / pageSize),
|
||||
};
|
||||
}
|
||||
|
||||
function transformPaginationToQuery(query) {
|
||||
const { pageSize, pageIndex, sortBy } = query;
|
||||
|
||||
return {
|
||||
page_size: pageSize,
|
||||
page: pageIndex + 1,
|
||||
...(sortBy.length > 0
|
||||
? {
|
||||
column_sort_by: sortBy[0].id,
|
||||
sort_order: sortBy[0].desc ? 'desc' : 'asc',
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Items view page.
|
||||
*/
|
||||
function ItemsViewPage({
|
||||
// #withAlertsActions.
|
||||
openAlert,
|
||||
@@ -19,10 +49,14 @@ function ItemsViewPage({
|
||||
|
||||
// #withItemsActions.
|
||||
setSelectedRowsItems,
|
||||
addItemsTableQueries
|
||||
addItemsTableQueries,
|
||||
|
||||
itemsTableQuery,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
const { pagination, isItemsFetching } = useItemsListContext();
|
||||
|
||||
// Handle delete action Item.
|
||||
const handleDeleteItem = ({ id }) => {
|
||||
openAlert('item-delete', { itemId: id });
|
||||
@@ -52,49 +86,49 @@ function ItemsViewPage({
|
||||
// Handle item make adjustment.
|
||||
const handleMakeAdjustment = ({ id }) => {
|
||||
openDialog('inventory-adjustment', { itemId: id });
|
||||
}
|
||||
};
|
||||
|
||||
// Handle fetch data once the page index, size or sort by of the table change.
|
||||
const handleFetchData = ({ pageIndex, pageSize, sortBy }) => {
|
||||
const handlePaginationChange = ({ pageSize, page }) => {
|
||||
addItemsTableQueries({
|
||||
page_size: pageSize,
|
||||
page: pageIndex,
|
||||
...(sortBy.length > 0
|
||||
? {
|
||||
column_sort_by: sortBy[0].id,
|
||||
sort_order: sortBy[0].desc ? 'desc' : 'asc',
|
||||
}
|
||||
: {}),
|
||||
// ...transformPaginationToQuery(query),
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
};
|
||||
|
||||
const controlledState = (state) => ({
|
||||
...state,
|
||||
pageIndex: itemsTableQuery.page - 1,
|
||||
});
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={['/items/:custom_view_id/custom_view', '/items']}
|
||||
>
|
||||
<ItemsViewsTabs />
|
||||
<ItemsDataTable
|
||||
tableProps={{
|
||||
payload: {
|
||||
onDeleteItem: handleDeleteItem,
|
||||
onEditItem: handleEditItem,
|
||||
onInactivateItem: handleInactiveItem,
|
||||
onActivateItem: handleActivateItem,
|
||||
onMakeAdjustment: handleMakeAdjustment
|
||||
},
|
||||
onFetchData: handleFetchData
|
||||
}}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
<>
|
||||
<ItemsViewsTabs />
|
||||
<ItemsDataTable
|
||||
tableProps={{
|
||||
payload: {
|
||||
onDeleteItem: handleDeleteItem,
|
||||
onEditItem: handleEditItem,
|
||||
onInactivateItem: handleInactiveItem,
|
||||
onActivateItem: handleActivateItem,
|
||||
onMakeAdjustment: handleMakeAdjustment,
|
||||
},
|
||||
...transformPaginationToProps(pagination),
|
||||
onPaginationChange: handlePaginationChange,
|
||||
progressBarLoading: isItemsFetching,
|
||||
// useControlledState: controlledState
|
||||
// progressBarLoading: true
|
||||
}}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertsActions,
|
||||
withItemsActions,
|
||||
withDialogActions
|
||||
withDialogActions,
|
||||
withItems(({ itemsTableQuery }) => ({ itemsTableQuery })),
|
||||
)(ItemsViewPage);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { compose } from 'utils';
|
||||
import { DashboardViewsTabs } from 'components';
|
||||
import { pick } from 'lodash';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import withItemsActions from 'containers/Items/withItemsActions';
|
||||
import withItems from 'containers/Items/withItems';
|
||||
|
||||
import { useItemsListContext } from './ItemsListProvider';
|
||||
|
||||
/**
|
||||
@@ -14,17 +16,22 @@ import { useItemsListContext } from './ItemsListProvider';
|
||||
function ItemsViewsTabs({
|
||||
// #withItemsActions
|
||||
addItemsTableQueries,
|
||||
|
||||
// #withItems
|
||||
itemsTableQuery
|
||||
}) {
|
||||
const { custom_view_id: customViewId = null } = useParams();
|
||||
const { itemsViews } = useItemsListContext();
|
||||
|
||||
// Mapped items views.
|
||||
const tabs = itemsViews.map((view) => ({
|
||||
...pick(view, ['name', 'id']),
|
||||
}));
|
||||
|
||||
// Handles the active tab change.
|
||||
const handleTabChange = (viewId) => {
|
||||
addItemsTableQueries({
|
||||
custom_view_id: viewId || null,
|
||||
page: 1,
|
||||
customViewId: viewId || null,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -32,7 +39,7 @@ function ItemsViewsTabs({
|
||||
<Navbar className="navbar--dashboard-views">
|
||||
<NavbarGroup align={Alignment.LEFT}>
|
||||
<DashboardViewsTabs
|
||||
initialViewId={customViewId}
|
||||
currentViewId={itemsTableQuery.customViewId}
|
||||
resourceName={'items'}
|
||||
tabs={tabs}
|
||||
onChange={handleTabChange}
|
||||
@@ -42,7 +49,8 @@ function ItemsViewsTabs({
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
withItems(({ itemsTableQuery }) => ({ itemsTableQuery })),
|
||||
withItemsActions,
|
||||
)(ItemsViewsTabs);
|
||||
|
||||
@@ -71,7 +71,7 @@ export const ItemTypeAccessor = (row) => {
|
||||
) : null;
|
||||
};
|
||||
|
||||
export const ItemsActionMenuList = ({
|
||||
export function ItemsActionMenuList({
|
||||
row: { original },
|
||||
payload: {
|
||||
onEditItem,
|
||||
@@ -80,9 +80,9 @@ export const ItemsActionMenuList = ({
|
||||
onMakeAdjustment,
|
||||
onDeleteItem,
|
||||
},
|
||||
}) => {
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
@@ -112,6 +112,7 @@ export const ItemsActionMenuList = ({
|
||||
<If condition={original.type === 'inventory'}>
|
||||
<MenuItem
|
||||
text={formatMessage({ id: 'make_adjustment' })}
|
||||
icon={<Icon icon={'swap-vert'} iconSize={16} />}
|
||||
onClick={safeCallback(onMakeAdjustment, original)}
|
||||
/>
|
||||
</If>
|
||||
|
||||
@@ -1,30 +1,15 @@
|
||||
import {connect} from 'react-redux';
|
||||
import {
|
||||
getResourceViews,
|
||||
} from 'store/customViews/customViews.selectors'
|
||||
import {
|
||||
getItemsCurrentPageFactory,
|
||||
getItemsPaginationMetaFactory,
|
||||
getItemsTableQueryFactory,
|
||||
getItemsCurrentViewIdFactory
|
||||
} from 'store/items/items.selectors';
|
||||
|
||||
export default (mapState) => {
|
||||
const getItemsCurrentPage = getItemsCurrentPageFactory();
|
||||
const getItemsPaginationMeta = getItemsPaginationMetaFactory();
|
||||
const getItemsTableQuery = getItemsTableQueryFactory();
|
||||
const getItemsCurrentViewId = getItemsCurrentViewIdFactory();
|
||||
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const mapped = {
|
||||
itemsViews: getResourceViews(state, props, 'items'),
|
||||
itemsCurrentPage: getItemsCurrentPage(state, props),
|
||||
itemsBulkSelected: state.items.bulkActions,
|
||||
itemsTableLoading: state.items.loading,
|
||||
itemsSelectedRows: state.items.selectedRows,
|
||||
itemsTableQuery: getItemsTableQuery(state, props),
|
||||
itemsPagination: getItemsPaginationMeta(state, props),
|
||||
itemsCurrentViewId: getItemsCurrentViewId(state, props),
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
|
||||
@@ -1,35 +1,7 @@
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
fetchItems,
|
||||
fetchItem,
|
||||
deleteItem,
|
||||
submitItem,
|
||||
editItem,
|
||||
deleteBulkItems,
|
||||
activateItem,
|
||||
inactiveItem,
|
||||
} from 'store/items/items.actions';
|
||||
import t from 'store/types';
|
||||
|
||||
export const mapDispatchToProps = (dispatch) => ({
|
||||
requestFetchItems: (query) => dispatch(fetchItems({ query })),
|
||||
requestFetchItem: (id) => dispatch(fetchItem({ id })),
|
||||
requestDeleteItem: (id) => dispatch(deleteItem({ id })),
|
||||
requestDeleteBulkItems: (ids) => dispatch(deleteBulkItems({ ids })),
|
||||
requestSubmitItem: (form) => dispatch(submitItem({ form })),
|
||||
requestEditItem: (id, form) => dispatch(editItem(id, form)),
|
||||
requestInactiveItem: (id) => dispatch(inactiveItem({ id })),
|
||||
requestActivateItem: (id) => dispatch(activateItem({ id })),
|
||||
addBulkActionItem: (id) =>
|
||||
dispatch({
|
||||
type: t.ITEM_BULK_ACTION_ADD,
|
||||
itemId: id,
|
||||
}),
|
||||
removeBulkActionItem: (id) =>
|
||||
dispatch({
|
||||
type: t.ITEM_BULK_ACTION_REMOVE,
|
||||
itemId: id,
|
||||
}),
|
||||
setItemsTableQuery: (key, value) =>
|
||||
dispatch({
|
||||
type: t.ITEMS_TABLE_QUERY_SET,
|
||||
@@ -41,12 +13,6 @@ export const mapDispatchToProps = (dispatch) => ({
|
||||
type: t.ITEMS_TABLE_QUERIES_ADD,
|
||||
payload: { queries },
|
||||
}),
|
||||
|
||||
changeItemsCurrentView: (id) =>
|
||||
dispatch({
|
||||
type: t.ITEMS_SET_CURRENT_VIEW,
|
||||
currentViewId: parseInt(id, 10),
|
||||
}),
|
||||
setSelectedRowsItems: (selectedRows) =>
|
||||
dispatch({
|
||||
type: t.ITEM_SELECTED_ROWS_SET,
|
||||
|
||||
@@ -68,7 +68,7 @@ export default function ItemsCategoryTable({
|
||||
sticky={true}
|
||||
selectionColumn={true}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
{...tableProps}
|
||||
noResults={'There is no items categories in table yet.'}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user