mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 22:30:31 +00:00
fix: items issues.
This commit is contained in:
@@ -32,7 +32,7 @@ function TableHeaderCell({ column, index }) {
|
|||||||
{...column.getSortByToggleProps({
|
{...column.getSortByToggleProps({
|
||||||
className: classNames('cell-inner', {
|
className: classNames('cell-inner', {
|
||||||
'text-overview': column.textOverview,
|
'text-overview': column.textOverview,
|
||||||
}),
|
})
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{column.render('Header')}
|
{column.render('Header')}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function TablePagination() {
|
|||||||
const pageIndex = page - 1;
|
const pageIndex = page - 1;
|
||||||
|
|
||||||
gotoPage(pageIndex);
|
gotoPage(pageIndex);
|
||||||
triggerOnPaginationChange({ page, pageSize });
|
triggerOnPaginationChange({ pageIndex, pageSize });
|
||||||
},
|
},
|
||||||
[gotoPage, triggerOnPaginationChange],
|
[gotoPage, triggerOnPaginationChange],
|
||||||
);
|
);
|
||||||
@@ -35,10 +35,12 @@ export default function TablePagination() {
|
|||||||
// Handles the page size changing.
|
// Handles the page size changing.
|
||||||
const handlePageSizeChange = useCallback(
|
const handlePageSizeChange = useCallback(
|
||||||
({ pageSize, page }) => {
|
({ pageSize, page }) => {
|
||||||
gotoPage(0);
|
const pageIndex = 0;
|
||||||
|
|
||||||
|
gotoPage(pageIndex);
|
||||||
setPageSize(pageSize);
|
setPageSize(pageSize);
|
||||||
|
|
||||||
triggerOnPaginationChange({ page, pageSize });
|
triggerOnPaginationChange({ pageIndex, pageSize });
|
||||||
},
|
},
|
||||||
[gotoPage, setPageSize, triggerOnPaginationChange],
|
[gotoPage, setPageSize, triggerOnPaginationChange],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function ItemsActionsBar({
|
|||||||
itemsSelectedRows,
|
itemsSelectedRows,
|
||||||
|
|
||||||
// #withItemActions
|
// #withItemActions
|
||||||
addItemsTableQueries,
|
setItemsTableState,
|
||||||
|
|
||||||
// #withAlertActions
|
// #withAlertActions
|
||||||
openAlert,
|
openAlert,
|
||||||
@@ -40,6 +40,7 @@ function ItemsActionsBar({
|
|||||||
// Items list context.
|
// Items list context.
|
||||||
const { itemsViews } = useItemsListContext();
|
const { itemsViews } = useItemsListContext();
|
||||||
|
|
||||||
|
// React intl.
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
// History context.
|
// History context.
|
||||||
@@ -52,9 +53,7 @@ function ItemsActionsBar({
|
|||||||
|
|
||||||
// Handle tab changing.
|
// Handle tab changing.
|
||||||
const handleTabChange = (viewId) => {
|
const handleTabChange = (viewId) => {
|
||||||
addItemsTableQueries({
|
setItemsTableState({ customViewId: viewId.id || null });
|
||||||
customViewId: viewId.id || null,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle cancel/confirm items bulk.
|
// Handle cancel/confirm items bulk.
|
||||||
@@ -115,8 +114,7 @@ function ItemsActionsBar({
|
|||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
</DashboardActionsBar>
|
</DashboardActionsBar>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
withItems(({ itemsSelectedRows }) => ({ itemsSelectedRows })),
|
withItems(({ itemsSelectedRows }) => ({ itemsSelectedRows })),
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { DataTable, Choose } from 'components';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { DataTable } from 'components';
|
||||||
|
|
||||||
import ItemsEmptyStatus from './ItemsEmptyStatus';
|
import ItemsEmptyStatus from './ItemsEmptyStatus';
|
||||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||||
@@ -9,134 +10,138 @@ import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
|||||||
|
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
|
|
||||||
import withSettings from 'containers/Settings/withSettings';
|
import withItems from 'containers/Items/withItems';
|
||||||
import { useItemsListContext } from './ItemsListProvider';
|
import withItemsActions from 'containers/Items/withItemsActions';
|
||||||
import { compose } from 'utils';
|
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||||
import {
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
QuantityOnHandCell,
|
|
||||||
SellPriceCell,
|
|
||||||
CostPriceCell,
|
|
||||||
ItemTypeAccessor,
|
|
||||||
ItemsActionsTableCell,
|
|
||||||
ItemsActionMenuList
|
|
||||||
} from './components';
|
|
||||||
|
|
||||||
// Items datatable.
|
import { useItemsListContext } from './ItemsListProvider';
|
||||||
|
import { useItemsTableColumns, ItemsActionMenuList } from './components';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Items datatable.
|
||||||
|
*/
|
||||||
function ItemsDataTable({
|
function ItemsDataTable({
|
||||||
|
// #withItemsActions
|
||||||
|
setItemsTableState,
|
||||||
|
|
||||||
|
// #withDialogAction
|
||||||
|
openDialog,
|
||||||
|
|
||||||
|
// #withAlertsActions
|
||||||
|
openAlert,
|
||||||
|
|
||||||
|
// #withItems
|
||||||
|
itemsTableState,
|
||||||
|
|
||||||
// #ownProps
|
// #ownProps
|
||||||
tableProps
|
tableProps,
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage } = useIntl();
|
// Items list context.
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
pagination,
|
pagination,
|
||||||
isItemsLoading,
|
isItemsLoading,
|
||||||
isEmptyStatus,
|
isEmptyStatus,
|
||||||
|
isItemsFetching,
|
||||||
} = useItemsListContext();
|
} = useItemsListContext();
|
||||||
|
|
||||||
// Datatable columns.
|
// Datatable columns.
|
||||||
const columns = useMemo(
|
const columns = useItemsTableColumns();
|
||||||
() => [
|
|
||||||
{
|
// History context.
|
||||||
Header: formatMessage({ id: 'item_name' }),
|
const history = useHistory();
|
||||||
accessor: 'name',
|
|
||||||
className: 'name',
|
|
||||||
width: 180,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: formatMessage({ id: 'item_code' }),
|
|
||||||
accessor: 'code',
|
|
||||||
className: 'code',
|
|
||||||
width: 120,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: formatMessage({ id: 'item_type' }),
|
|
||||||
accessor: ItemTypeAccessor,
|
|
||||||
className: 'item_type',
|
|
||||||
width: 120,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: formatMessage({ id: 'category' }),
|
|
||||||
accessor: 'category.name',
|
|
||||||
className: 'category',
|
|
||||||
width: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: formatMessage({ id: 'sell_price' }),
|
|
||||||
Cell: SellPriceCell,
|
|
||||||
accessor: 'sell_price',
|
|
||||||
className: 'sell-price',
|
|
||||||
width: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: formatMessage({ id: 'cost_price' }),
|
|
||||||
Cell: CostPriceCell,
|
|
||||||
accessor: 'cost_price',
|
|
||||||
className: 'cost-price',
|
|
||||||
width: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: formatMessage({ id: 'quantity_on_hand' }),
|
|
||||||
accessor: 'quantity_on_hand',
|
|
||||||
Cell: QuantityOnHandCell,
|
|
||||||
width: 140,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'actions',
|
|
||||||
Cell: ItemsActionsTableCell,
|
|
||||||
width: 60,
|
|
||||||
skeletonWidthMin: 100,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[formatMessage],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Table row class names.
|
// Table row class names.
|
||||||
const rowClassNames = (row) => ({
|
const rowClassNames = (row) => ({
|
||||||
inactive: !row.original.active,
|
inactive: !row.original.active,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle fetch data once the page index, size or sort by of the table change.
|
||||||
|
const handleFetchData = React.useCallback(
|
||||||
|
({ pageSize, pageIndex, sortBy }) => {
|
||||||
|
setItemsTableState({
|
||||||
|
pageIndex,
|
||||||
|
pageSize,
|
||||||
|
sortBy,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setItemsTableState],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle delete action Item.
|
||||||
|
const handleDeleteItem = ({ id }) => {
|
||||||
|
openAlert('item-delete', { itemId: id });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle cancel/confirm item inactive.
|
||||||
|
const handleInactiveItem = ({ id }) => {
|
||||||
|
openAlert('item-inactivate', { itemId: id });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle cancel/confirm item activate.
|
||||||
|
const handleActivateItem = ({ id }) => {
|
||||||
|
openAlert('item-activate', { itemId: id });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle Edit item.
|
||||||
|
const handleEditItem = ({ id }) => {
|
||||||
|
history.push(`/items/${id}/edit`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle item make adjustment.
|
||||||
|
const handleMakeAdjustment = ({ id }) => {
|
||||||
|
openDialog('inventory-adjustment', { itemId: id });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cannot continue in case the items has empty status.
|
||||||
|
if (isEmptyStatus) {
|
||||||
|
return <ItemsEmptyStatus />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||||
<Choose>
|
<DataTable
|
||||||
<Choose.When condition={isEmptyStatus}>
|
columns={columns}
|
||||||
<ItemsEmptyStatus />
|
data={items}
|
||||||
</Choose.When>
|
initialState={itemsTableState}
|
||||||
|
loading={isItemsLoading}
|
||||||
<Choose.Otherwise>
|
headerLoading={isItemsLoading}
|
||||||
<DataTable
|
progressBarLoading={isItemsFetching}
|
||||||
columns={columns}
|
noInitialFetch={true}
|
||||||
data={items}
|
selectionColumn={true}
|
||||||
loading={isItemsLoading}
|
spinnerProps={{ size: 30 }}
|
||||||
headerLoading={isItemsLoading}
|
expandable={false}
|
||||||
noInitialFetch={true}
|
sticky={true}
|
||||||
selectionColumn={true}
|
rowClassNames={rowClassNames}
|
||||||
spinnerProps={{ size: 30 }}
|
pagination={true}
|
||||||
expandable={false}
|
manualSortBy={true}
|
||||||
sticky={true}
|
manualPagination={true}
|
||||||
rowClassNames={rowClassNames}
|
pagesCount={pagination.pagesCount}
|
||||||
pagination={true}
|
autoResetSortBy={false}
|
||||||
manualSortBy={true}
|
autoResetPage={true}
|
||||||
pagesCount={1}
|
TableLoadingRenderer={TableSkeletonRows}
|
||||||
autoResetSortBy={false}
|
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||||
autoResetPage={true}
|
ContextMenu={ItemsActionMenuList}
|
||||||
manualPagination={true}
|
onFetchData={handleFetchData}
|
||||||
TableLoadingRenderer={TableSkeletonRows}
|
payload={{
|
||||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
onDeleteItem: handleDeleteItem,
|
||||||
|
onEditItem: handleEditItem,
|
||||||
pageSize={pagination.pageSize}
|
onInactivateItem: handleInactiveItem,
|
||||||
pageIndex={pagination.page - 1}
|
onActivateItem: handleActivateItem,
|
||||||
ContextMenu={ItemsActionMenuList}
|
onMakeAdjustment: handleMakeAdjustment,
|
||||||
{...tableProps}
|
}}
|
||||||
/>
|
noResults={'There is no items in the table yet.'}
|
||||||
</Choose.Otherwise>
|
{...tableProps}
|
||||||
</Choose>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
withSettings(({ organizationSettings }) => ({
|
withItemsActions,
|
||||||
baseCurrency: organizationSettings?.baseCurrency,
|
withAlertsActions,
|
||||||
})),
|
withDialogActions,
|
||||||
|
withItems(({ itemsTableState }) => ({ itemsTableState })),
|
||||||
)(ItemsDataTable);
|
)(ItemsDataTable);
|
||||||
|
|||||||
@@ -3,34 +3,38 @@ import { compose } from 'utils';
|
|||||||
|
|
||||||
import 'style/pages/Items/List.scss';
|
import 'style/pages/Items/List.scss';
|
||||||
|
|
||||||
import ItemsViewPage from './ItemsViewPage';
|
|
||||||
import ItemsActionsBar from './ItemsActionsBar';
|
|
||||||
import ItemsAlerts from './ItemsAlerts';
|
|
||||||
|
|
||||||
import { ItemsListProvider } from './ItemsListProvider';
|
|
||||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
|
|
||||||
import withItems from 'containers/Items/withItems';
|
import ItemsActionsBar from './ItemsActionsBar';
|
||||||
|
import ItemsAlerts from './ItemsAlerts';
|
||||||
|
import ItemsViewsTabs from './ItemsViewsTabs';
|
||||||
|
import ItemsDataTable from './ItemsDataTable';
|
||||||
|
|
||||||
|
import { ItemsListProvider } from './ItemsListProvider';
|
||||||
|
import withItems from './withItems';
|
||||||
|
import { transformTableStateToQuery } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Items list.
|
* Items list.
|
||||||
*/
|
*/
|
||||||
function ItemsList({
|
function ItemsList({
|
||||||
// #withItems
|
// #withItems
|
||||||
itemsTableQuery
|
itemsTableState,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<ItemsListProvider query={itemsTableQuery}>
|
<ItemsListProvider query={transformTableStateToQuery(itemsTableState)}>
|
||||||
<ItemsActionsBar />
|
<ItemsActionsBar />
|
||||||
|
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<ItemsViewPage />
|
<ItemsViewsTabs />
|
||||||
|
<ItemsDataTable />
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
|
|
||||||
<ItemsAlerts />
|
<ItemsAlerts />
|
||||||
</ItemsListProvider>
|
</ItemsListProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
withItems(({ itemsTableQuery }) => ({ itemsTableQuery })),
|
withItems(({ itemsTableState }) => ({ itemsTableState })),
|
||||||
)(ItemsList);
|
)(ItemsList);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ function ItemsListProvider({
|
|||||||
// Change page title dispatcher.
|
// Change page title dispatcher.
|
||||||
const changePageTitle = useDashboardPageTitle();
|
const changePageTitle = useDashboardPageTitle();
|
||||||
|
|
||||||
|
// Changeas the page title once the page mount.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
changePageTitle(formatMessage({ id: 'items_list' }));
|
changePageTitle(formatMessage({ id: 'items_list' }));
|
||||||
}, [changePageTitle, formatMessage]);
|
}, [changePageTitle, formatMessage]);
|
||||||
|
|||||||
@@ -1,134 +0,0 @@
|
|||||||
import React, { useMemo } from 'react';
|
|
||||||
import { useHistory } from 'react-router-dom';
|
|
||||||
|
|
||||||
import ItemsViewsTabs from './ItemsViewsTabs';
|
|
||||||
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,
|
|
||||||
|
|
||||||
// #withDialogActions
|
|
||||||
openDialog,
|
|
||||||
|
|
||||||
// #withItemsActions.
|
|
||||||
setSelectedRowsItems,
|
|
||||||
addItemsTableQueries,
|
|
||||||
|
|
||||||
itemsTableQuery,
|
|
||||||
}) {
|
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
const { pagination, isItemsFetching } = useItemsListContext();
|
|
||||||
|
|
||||||
// Handle delete action Item.
|
|
||||||
const handleDeleteItem = ({ id }) => {
|
|
||||||
openAlert('item-delete', { itemId: id });
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle cancel/confirm item inactive.
|
|
||||||
const handleInactiveItem = ({ id }) => {
|
|
||||||
openAlert('item-inactivate', { itemId: id });
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle cancel/confirm item activate.
|
|
||||||
const handleActivateItem = ({ id }) => {
|
|
||||||
openAlert('item-activate', { itemId: id });
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle select item rows.
|
|
||||||
const handleSelectedRowsChange = (selectedRows) => {
|
|
||||||
const selectedRowsIds = selectedRows.map((r) => r.id);
|
|
||||||
setSelectedRowsItems(selectedRowsIds);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle Edit item.
|
|
||||||
const handleEditItem = ({ id }) => {
|
|
||||||
history.push(`/items/${id}/edit`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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 handlePaginationChange = ({ pageSize, page }) => {
|
|
||||||
addItemsTableQueries({
|
|
||||||
// ...transformPaginationToQuery(query),
|
|
||||||
page,
|
|
||||||
pageSize,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const controlledState = (state) => ({
|
|
||||||
...state,
|
|
||||||
pageIndex: itemsTableQuery.page - 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<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,
|
|
||||||
withItems(({ itemsTableQuery }) => ({ itemsTableQuery })),
|
|
||||||
)(ItemsViewPage);
|
|
||||||
@@ -15,10 +15,10 @@ import { useItemsListContext } from './ItemsListProvider';
|
|||||||
*/
|
*/
|
||||||
function ItemsViewsTabs({
|
function ItemsViewsTabs({
|
||||||
// #withItemsActions
|
// #withItemsActions
|
||||||
addItemsTableQueries,
|
setItemsTableState,
|
||||||
|
|
||||||
// #withItems
|
// #withItems
|
||||||
itemsTableQuery
|
itemsCustomViewId
|
||||||
}) {
|
}) {
|
||||||
const { itemsViews } = useItemsListContext();
|
const { itemsViews } = useItemsListContext();
|
||||||
|
|
||||||
@@ -29,8 +29,8 @@ function ItemsViewsTabs({
|
|||||||
|
|
||||||
// Handles the active tab change.
|
// Handles the active tab change.
|
||||||
const handleTabChange = (viewId) => {
|
const handleTabChange = (viewId) => {
|
||||||
addItemsTableQueries({
|
setItemsTableState({
|
||||||
page: 1,
|
pageIndex: 0,
|
||||||
customViewId: viewId || null,
|
customViewId: viewId || null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -39,7 +39,7 @@ function ItemsViewsTabs({
|
|||||||
<Navbar className="navbar--dashboard-views">
|
<Navbar className="navbar--dashboard-views">
|
||||||
<NavbarGroup align={Alignment.LEFT}>
|
<NavbarGroup align={Alignment.LEFT}>
|
||||||
<DashboardViewsTabs
|
<DashboardViewsTabs
|
||||||
currentViewId={itemsTableQuery.customViewId}
|
currentViewId={itemsCustomViewId}
|
||||||
resourceName={'items'}
|
resourceName={'items'}
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
onChange={handleTabChange}
|
onChange={handleTabChange}
|
||||||
@@ -51,6 +51,8 @@ function ItemsViewsTabs({
|
|||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
withRouter,
|
withRouter,
|
||||||
withItems(({ itemsTableQuery }) => ({ itemsTableQuery })),
|
withItems(({ itemsTableState }) => ({
|
||||||
|
itemsCustomViewId: itemsTableState?.customViewId
|
||||||
|
})),
|
||||||
withItemsActions,
|
withItemsActions,
|
||||||
)(ItemsViewsTabs);
|
)(ItemsViewsTabs);
|
||||||
|
|||||||
@@ -136,3 +136,67 @@ export const ItemsActionsTableCell = (props) => {
|
|||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all items table columns.
|
||||||
|
*/
|
||||||
|
export const useItemsTableColumns = () => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
return React.useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
Header: formatMessage({ id: 'item_name' }),
|
||||||
|
accessor: 'name',
|
||||||
|
className: 'name',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: formatMessage({ id: 'item_code' }),
|
||||||
|
accessor: 'code',
|
||||||
|
className: 'code',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: formatMessage({ id: 'item_type' }),
|
||||||
|
accessor: ItemTypeAccessor,
|
||||||
|
className: 'item_type',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: formatMessage({ id: 'category' }),
|
||||||
|
accessor: 'category.name',
|
||||||
|
className: 'category',
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: formatMessage({ id: 'sell_price' }),
|
||||||
|
Cell: SellPriceCell,
|
||||||
|
accessor: 'sell_price',
|
||||||
|
className: 'sell-price',
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: formatMessage({ id: 'cost_price' }),
|
||||||
|
Cell: CostPriceCell,
|
||||||
|
accessor: 'cost_price',
|
||||||
|
className: 'cost-price',
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: formatMessage({ id: 'quantity_on_hand' }),
|
||||||
|
accessor: 'quantity_on_hand',
|
||||||
|
Cell: QuantityOnHandCell,
|
||||||
|
width: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'actions',
|
||||||
|
Cell: ItemsActionsTableCell,
|
||||||
|
width: 60,
|
||||||
|
skeletonWidthMin: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[formatMessage],
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import {
|
import {
|
||||||
getItemsTableQueryFactory,
|
getItemsTableStateFactory,
|
||||||
} from 'store/items/items.selectors';
|
} from 'store/items/items.selectors';
|
||||||
|
|
||||||
export default (mapState) => {
|
export default (mapState) => {
|
||||||
const getItemsTableQuery = getItemsTableQueryFactory();
|
const getItemsTableState = getItemsTableStateFactory();
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => {
|
const mapStateToProps = (state, props) => {
|
||||||
const mapped = {
|
const mapped = {
|
||||||
itemsSelectedRows: state.items.selectedRows,
|
itemsSelectedRows: state.items.selectedRows,
|
||||||
itemsTableQuery: getItemsTableQuery(state, props),
|
itemsTableState: getItemsTableState(state, props),
|
||||||
};
|
};
|
||||||
return mapState ? mapState(mapped, state, props) : mapped;
|
return mapState ? mapState(mapped, state, props) : mapped;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import t from 'store/types';
|
import { setItemsTableState }from 'store/items/items.actions';
|
||||||
|
|
||||||
export const mapDispatchToProps = (dispatch) => ({
|
export const mapDispatchToProps = (dispatch) => ({
|
||||||
setItemsTableQuery: (key, value) =>
|
setItemsTableState: (queries) => dispatch(setItemsTableState(queries)),
|
||||||
dispatch({
|
// setSelectedRowsItems: (selectedRows) =>
|
||||||
type: t.ITEMS_TABLE_QUERY_SET,
|
// dispatch({
|
||||||
key,
|
// type: t.ITEM_SELECTED_ROWS_SET,
|
||||||
value,
|
// payload: { selectedRows },
|
||||||
}),
|
// }),
|
||||||
addItemsTableQueries: (queries) =>
|
|
||||||
dispatch({
|
|
||||||
type: t.ITEMS_TABLE_QUERIES_ADD,
|
|
||||||
payload: { queries },
|
|
||||||
}),
|
|
||||||
setSelectedRowsItems: (selectedRows) =>
|
|
||||||
dispatch({
|
|
||||||
type: t.ITEM_SELECTED_ROWS_SET,
|
|
||||||
payload: { selectedRows },
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(null, mapDispatchToProps);
|
export default connect(null, mapDispatchToProps);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||||
import { defaultTo } from 'lodash';
|
import { defaultTo } from 'lodash';
|
||||||
import ApiService from 'services/ApiService';
|
import ApiService from 'services/ApiService';
|
||||||
import { transformResponse } from 'utils';
|
import { transformPagination, transformResponse } from 'utils';
|
||||||
|
|
||||||
const defaultPagination = {
|
const defaultPagination = {
|
||||||
pageSize: 12,
|
pageSize: 12,
|
||||||
@@ -57,7 +57,9 @@ export function useDeleteItem(props) {
|
|||||||
const transformItemsResponse = (response) => {
|
const transformItemsResponse = (response) => {
|
||||||
return {
|
return {
|
||||||
items: response.data.items,
|
items: response.data.items,
|
||||||
pagination: transformResponse(response.data.pagination),
|
pagination: transformPagination(
|
||||||
|
transformResponse(response.data.pagination)
|
||||||
|
),
|
||||||
filterMeta: transformResponse(response.data.filter_meta),
|
filterMeta: transformResponse(response.data.filter_meta),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import t from 'store/types';
|
||||||
|
|
||||||
|
export const setItemsTableState = (queries) => {
|
||||||
|
return {
|
||||||
|
type: t.ITEMS_TABLE_STATE_SET,
|
||||||
|
payload: { queries },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setSelectedRowsItems = () => {};
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { createReducer } from '@reduxjs/toolkit';
|
import { createReducer } from '@reduxjs/toolkit';
|
||||||
import {
|
import {
|
||||||
createTableQueryReducers,
|
createTableStateReducers,
|
||||||
} from 'store/journalNumber.reducer';
|
} from 'store/tableState.reducer';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
tableQuery: {
|
tableState: {
|
||||||
pageSize: 12,
|
pageSize: 12,
|
||||||
page: 1,
|
pageIndex: 0,
|
||||||
|
filters: [],
|
||||||
},
|
},
|
||||||
selectedRows: [],
|
selectedRows: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default createReducer(initialState, {
|
export default createReducer(initialState, {
|
||||||
...createTableQueryReducers('ITEMS'),
|
...createTableStateReducers('ITEMS'),
|
||||||
});
|
});
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
import { paginationLocationQuery } from 'store/selectors';
|
import { paginationLocationQuery } from 'store/selectors';
|
||||||
import { createDeepEqualSelector } from 'utils';
|
import { createDeepEqualSelector } from 'utils';
|
||||||
|
|
||||||
const itemsTableQuerySelector = (state) => state.items.tableQuery;
|
const itemsTableStateSelector = (state) => state.items.tableState;
|
||||||
|
|
||||||
// Get items table query marged with location query.
|
// Get items table state marged with location query.
|
||||||
export const getItemsTableQueryFactory = () =>
|
export const getItemsTableStateFactory = () =>
|
||||||
createDeepEqualSelector(
|
createDeepEqualSelector(
|
||||||
paginationLocationQuery,
|
paginationLocationQuery,
|
||||||
itemsTableQuerySelector,
|
itemsTableStateSelector,
|
||||||
(locationQuery, tableQuery) => {
|
(locationQuery, tableState) => {
|
||||||
return {
|
return {
|
||||||
...locationQuery,
|
...locationQuery,
|
||||||
...tableQuery,
|
...tableState,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,17 +1,4 @@
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
ITEMS_SET: 'ITEMS_SET',
|
ITEMS_TABLE_STATE_SET: 'ITEMS/TABLE_STATE_SET',
|
||||||
ITEM_SET: 'ITEM_SET',
|
};
|
||||||
ITEMS_PAGE_SET: 'ITEMS_PAGE_SET',
|
|
||||||
ITEMS_PAGINATION_SET: 'ITEMS_PAGINATION_SET',
|
|
||||||
ITEM_DELETE: 'ITEM_DELETE',
|
|
||||||
ITEM_BULK_ACTION_ADD: 'ITEM_BULK_ACTION_ADD',
|
|
||||||
ITEM_BULK_ACTION_REMOVE: 'ITEM_BULK_ACTION_REMOVE',
|
|
||||||
|
|
||||||
ITEMS_TABLE_QUERY_SET: 'ITEMS/TABLE_QUERY_SET',
|
|
||||||
ITEMS_TABLE_QUERIES_ADD: 'ITEMS/TABLE_QUERIES_ADD',
|
|
||||||
|
|
||||||
ITEMS_TABLE_LOADING: 'ITEMS_TABLE_LOADING',
|
|
||||||
ITEMS_SET_CURRENT_VIEW: 'ITEMS_SET_CURRENT_VIEW',
|
|
||||||
ITEMS_BULK_DELETE: 'ITEMS_BULK_DELETE',
|
|
||||||
ITEM_SELECTED_ROWS_SET: 'ITEM_SELECTED_ROWS_SET',
|
|
||||||
};
|
|
||||||
18
client/src/store/tableState.reducer.js
Normal file
18
client/src/store/tableState.reducer.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
const TYPES = {
|
||||||
|
TABLE_STATE_SET: 'TABLE_STATE_SET',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createTableStateReducers = (RESOURCE_NAME) => ({
|
||||||
|
/**
|
||||||
|
* Resource table state set.
|
||||||
|
*/
|
||||||
|
[`${RESOURCE_NAME}/${TYPES.TABLE_STATE_SET}`]: (state, action) => {
|
||||||
|
const { queries } = action.payload;
|
||||||
|
|
||||||
|
state.tableState = {
|
||||||
|
...state.tableState,
|
||||||
|
...queries,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -487,4 +487,52 @@ export const isTableEmptyStatus = ({ data, pagination, filterMeta }) => {
|
|||||||
_.isEmpty(filterMeta.view),
|
_.isEmpty(filterMeta.view),
|
||||||
pagination.page === 1,
|
pagination.page === 1,
|
||||||
].every(cond => cond === true)
|
].every(cond => cond === true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the pagination meta to table props.
|
||||||
|
*/
|
||||||
|
export function getPagesCountFromPaginationMeta(pagination) {
|
||||||
|
const { pageSize, total } = pagination;
|
||||||
|
|
||||||
|
return Math.ceil(total / pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the table state to url query.
|
||||||
|
*/
|
||||||
|
export function transformTableStateToQuery(tableState) {
|
||||||
|
const { pageSize, pageIndex, customViewId, sortBy } = tableState;
|
||||||
|
|
||||||
|
const query = {
|
||||||
|
pageSize,
|
||||||
|
page: pageIndex + 1,
|
||||||
|
...(customViewId ? { customViewId } : {}),
|
||||||
|
...(Array.isArray(sortBy) && sortBy.length > 0
|
||||||
|
? {
|
||||||
|
column_sort_by: sortBy[0].id,
|
||||||
|
sort_order: sortBy[0].desc ? 'desc' : 'asc',
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
return transfromToSnakeCase(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the global table state to table state.
|
||||||
|
*/
|
||||||
|
export function globalTableStateToTable(globalState) {
|
||||||
|
return {
|
||||||
|
..._.omit(globalState, ['customViewId']),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the pagination meta repsonse.
|
||||||
|
*/
|
||||||
|
export function transformPagination(pagination) {
|
||||||
|
return {
|
||||||
|
...pagination,
|
||||||
|
pagesCount: getPagesCountFromPaginationMeta(pagination),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user