Merge branch 'feature/react-query' of https://github.com/abouolia/Bigcapital into feature/react-query

This commit is contained in:
elforjani3
2021-02-09 21:10:15 +02:00
32 changed files with 497 additions and 882 deletions

View File

@@ -67,7 +67,7 @@ function ItemCategoryForm({
const afterSubmit = () => {
closeDialog(dialogName);
};
// Handle the response success/
// Handle the response success.
const onSuccess = ({ response }) => {
AppToaster.show({
message: formatMessage({
@@ -80,7 +80,9 @@ function ItemCategoryForm({
afterSubmit(response);
};
// Handle the response error.
const onError = (errors) => {
const onError = (error) => {
const { response: { data: { errors } } } = error;
transformErrors(errors, { setErrors });
setSubmitting(false);
};

View File

@@ -1,195 +0,0 @@
import React, { useCallback, useMemo } from 'react';
import {
Button,
Popover,
Menu,
Intent,
MenuItem,
MenuDivider,
Position,
} from '@blueprintjs/core';
import { useIntl } from 'react-intl';
import moment from 'moment';
import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import { DataTable, Icon } from 'components';
import { CLASSES } from 'common/classes';
import {
PublishAccessor,
TypeAccessor,
} from './components';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withInventoryAdjustmentActions from './withInventoryAdjustmentActions';
import { compose, saveInvoke } from 'utils';
function InventoryAdjustmentDataTable({
// withInventoryAdjustmentsActions
addInventoryAdjustmentTableQueries,
// #ownProps
isLoading,
inventoryAdjustments,
pagination,
onDeleteInventoryAdjustment,
onSelectedRowsChange,
}) {
const { formatMessage } = useIntl();
const handleDeleteInventoryAdjustment = useCallback(
(_adjustment) => () => {
saveInvoke(onDeleteInventoryAdjustment, _adjustment);
},
[onDeleteInventoryAdjustment],
);
const actionMenuList = useCallback(
(adjustment) => (
<Menu>
<MenuItem
icon={<Icon icon="reader-18" />}
text={formatMessage({ id: 'view_details' })}
/>
<MenuDivider />
<MenuItem
text={formatMessage({ id: 'delete_adjustment' })}
intent={Intent.DANGER}
onClick={handleDeleteInventoryAdjustment(adjustment)}
icon={<Icon icon="trash-16" iconSize={16} />}
/>
</Menu>
),
[handleDeleteInventoryAdjustment, formatMessage],
);
const onRowContextMenu = useCallback(
(cell) => actionMenuList(cell.row.original),
[actionMenuList],
);
const columns = useMemo(
() => [
{
id: 'date',
Header: formatMessage({ id: 'date' }),
accessor: (r) => moment(r.date).format('YYYY MMM DD'),
width: 115,
className: 'date',
},
{
id: 'type',
Header: formatMessage({ id: 'type' }),
accessor: TypeAccessor,
className: 'type',
width: 100,
},
{
id: 'reason',
Header: formatMessage({ id: 'reason' }),
accessor: 'reason',
className: 'reason',
width: 115,
},
{
id: 'reference_no',
Header: formatMessage({ id: 'reference_no' }),
accessor: 'reference_no',
className: 'reference_no',
width: 100,
},
{
id: 'publish',
Header: formatMessage({ id: 'status' }),
accessor: PublishAccessor,
width: 95,
className: 'publish',
},
{
id: 'description',
Header: formatMessage({ id: 'description' }),
accessor: 'description',
disableSorting: true,
width: 85,
className: 'description',
},
{
id: 'created_at',
Header: formatMessage({ id: 'created_at' }),
accessor: (r) => moment(r.created_at).format('YYYY MMM DD'),
width: 125,
className: 'created_at',
},
{
id: 'actions',
Header: '',
Cell: ({ cell }) => (
<Popover
content={actionMenuList(cell.row.original)}
position={Position.RIGHT_BOTTOM}
>
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
</Popover>
),
className: 'actions',
width: 50,
disableResizing: true,
},
],
[actionMenuList, formatMessage],
);
const handleDataTableFetchData = useCallback(
({ pageSize, pageIndex, sortBy }) => {
addInventoryAdjustmentTableQueries({
...(sortBy.length > 0
? {
column_sort_by: sortBy[0].id,
sort_order: sortBy[0].desc ? 'desc' : 'asc',
}
: {}),
page_size: pageSize,
page: pageIndex + 1,
});
},
[addInventoryAdjustmentTableQueries],
);
const handleSelectedRowsChange = useCallback(
(selectedRows) => {
onSelectedRowsChange &&
onSelectedRowsChange(selectedRows.map((s) => s.original));
},
[onSelectedRowsChange],
);
return (
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
<DataTable
columns={columns}
data={inventoryAdjustments}
onFetchData={handleDataTableFetchData}
manualSortBy={true}
selectionColumn={true}
noInitialFetch={true}
onSelectedRowsChange={handleSelectedRowsChange}
rowContextMenu={onRowContextMenu}
pagination={true}
autoResetSortBy={false}
autoResetPage={false}
isLoading={isLoading}
noResults={'There is no inventory adjustments transactions yet.'}
// pagesCount={inventoryAdjustmentsPagination.pagesCount}
// initialPageSize={inventoryAdjustmentsPagination.pageSize}
// initialPageIndex={inventoryAdjustmentsPagination.page - 1}
/>
</div>
);
}
export default compose(
withRouter,
withDialogActions,
withInventoryAdjustmentActions,
)(InventoryAdjustmentDataTable);

View File

@@ -6,12 +6,12 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import InventoryAdjustmentsAlerts from './InventoryAdjustmentsAlerts';
import { InventoryAdjustmentsProvider } from './InventoryAdjustmentsProvider';
import InventoryAdjustmentView from './InventoryAdjustmentView';
import InventoryAdjustmentTable from './InventoryAdjustmentTable';
import withInventoryAdjustments from './withInventoryAdjustments';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import { compose } from 'utils';
import { compose, transformTableStateToQuery } from 'utils';
/**
* Inventory Adjustment List.
@@ -21,18 +21,21 @@ function InventoryAdjustmentList({
changePageTitle,
// #withInventoryAdjustments
inventoryAdjustmentTableQuery,
inventoryAdjustmentTableState,
}) {
const { formatMessage } = useIntl();
// Changes the dashboard title once the page mount.
useEffect(() => {
changePageTitle(formatMessage({ id: 'inventory_adjustment_list' }));
}, [changePageTitle, formatMessage]);
return (
<InventoryAdjustmentsProvider query={inventoryAdjustmentTableQuery}>
<InventoryAdjustmentsProvider
query={transformTableStateToQuery(inventoryAdjustmentTableState)}
>
<DashboardPageContent>
<InventoryAdjustmentView />
<InventoryAdjustmentTable />
<InventoryAdjustmentsAlerts />
</DashboardPageContent>
</InventoryAdjustmentsProvider>
@@ -41,7 +44,7 @@ function InventoryAdjustmentList({
export default compose(
withDashboardActions,
withInventoryAdjustments(({ inventoryAdjustmentTableQuery }) => ({
inventoryAdjustmentTableQuery,
withInventoryAdjustments(({ inventoryAdjustmentTableState }) => ({
inventoryAdjustmentTableState,
})),
)(InventoryAdjustmentList);

View File

@@ -0,0 +1,101 @@
import React, { useCallback } from 'react';
import classNames from 'classnames';
import { DataTable } from 'components';
import { CLASSES } from 'common/classes';
import { useInventoryAdjustmentsColumns, ActionsMenu } from './components';
import withAlertsActions from 'containers/Alert/withAlertActions';
import withInventoryAdjustmentActions from './withInventoryAdjustmentActions';
import { useInventoryAdjustmentsContext } from './InventoryAdjustmentsProvider';
import withInventoryAdjustments from './withInventoryAdjustments';
import { compose } from 'utils';
/**
* Inventory adjustments datatable.
*/
function InventoryAdjustmentDataTable({
// #withInventoryAdjustmentsActions
setInventoryAdjustmentTableState,
// #withInventoryAdjustments
inventoryAdjustmentTableState,
// #withAlertsActions
openAlert,
// #ownProps
tableProps
}) {
const {
isAdjustmentsLoading,
isAdjustmentsFetching,
inventoryAdjustments,
pagination
} = useInventoryAdjustmentsContext();
// Handle delete inventory adjustment transaction.
const handleDeleteAdjustment = ({ id }) => {
openAlert('inventory-adjustment-delete', { inventoryId: id });
};
// Inventory adjustments columns.
const columns = useInventoryAdjustmentsColumns();
// Handle the table fetch data once states changing.
const handleDataTableFetchData = useCallback(
({ pageSize, pageIndex, sortBy }) => {
setInventoryAdjustmentTableState({
pageSize,
pageIndex,
sortBy
})
},
[setInventoryAdjustmentTableState],
);
return (
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
<DataTable
columns={columns}
data={inventoryAdjustments}
loading={isAdjustmentsLoading}
headerLoading={isAdjustmentsLoading}
progressBarLoading={isAdjustmentsFetching}
initialState={inventoryAdjustmentTableState}
noInitialFetch={true}
onFetchData={handleDataTableFetchData}
manualSortBy={true}
selectionColumn={true}
pagination={true}
pagesCount={pagination.pagesCount}
autoResetSortBy={false}
autoResetPage={false}
payload={{
onDelete: handleDeleteAdjustment,
}}
ContextMenu={ActionsMenu}
noResults={'There is no inventory adjustments transactions yet.'}
{...tableProps}
/>
</div>
);
}
export default compose(
withAlertsActions,
withInventoryAdjustmentActions,
withInventoryAdjustments(({ inventoryAdjustmentTableState }) => ({
inventoryAdjustmentTableState,
})),
)(InventoryAdjustmentDataTable);

View File

@@ -1,6 +1,6 @@
import React from 'react';
import InventoryAdjustmentDataTable from './InventoryAdjustmentDataTable';
import withAlertsActions from 'containers/Alert/withAlertActions';
import { useInventoryAdjustmentsContext } from './InventoryAdjustmentsProvider';
import { compose } from 'utils';
@@ -11,16 +11,7 @@ function InventoryAdjustmentsView({
// #withAlertsActions.
openAlert,
}) {
const {
isAdjustmentsLoading,
inventoryAdjustments,
} = useInventoryAdjustmentsContext();
// Handle delete inventory adjustment transaction.
const handleDeleteInventoryAdjustment = ({ id }) => {
openAlert('inventory-adjustment-delete', { inventoryId: id });
};
return (
<InventoryAdjustmentDataTable
inventoryAdjustments={inventoryAdjustments}

View File

@@ -3,7 +3,7 @@ import InventoryAdjustmentDeleteAlert from 'containers/Alerts/Items/InventoryAdj
export default function InventoryAdjustmentsAlerts() {
return (
<div>
<div className={'inventory-adjustments-alert'}>
<InventoryAdjustmentDeleteAlert name={'inventory-adjustment-delete'} />
</div>
);

View File

@@ -8,19 +8,19 @@ const InventoryAdjustmentsContext = createContext();
* Accounts chart data provider.
*/
function InventoryAdjustmentsProvider({ query, ...props }) {
// Handles the inventory adjustments fethcing of the given query.
const {
isFetching: isAdjustmentsLoading,
data: {
transactions: inventoryAdjustments,
pagination,
},
} = useInventoryAdjustments(query);
isLoading: isAdjustmentsLoading,
isFetching: isAdjustmentsFetching,
data: { transactions: inventoryAdjustments, pagination },
} = useInventoryAdjustments(query, { keepPreviousData: true });
// Provider payload.
const provider = {
inventoryAdjustments,
isAdjustmentsLoading,
pagination
isAdjustmentsFetching,
pagination,
};
return (

View File

@@ -10,6 +10,7 @@ import {
Popover,
} from '@blueprintjs/core';
import { useIntl, FormattedMessage as T } from 'react-intl';
import moment from 'moment';
import { formatMessage } from 'services/intl';
import { isNumber } from 'lodash';
import { Icon, Money, If } from 'components';
@@ -30,6 +31,9 @@ export const PublishAccessor = (r) => {
);
};
/**
* Type column accessor.
*/
export const TypeAccessor = (row) => {
return row.type ? (
<Tag minimal={true} round={true} intent={Intent.NONE}>
@@ -40,6 +44,9 @@ export const TypeAccessor = (row) => {
);
};
/**
* Item type accessor.
*/
export const ItemCodeAccessor = (row) =>
row.type ? (
<Tag minimal={true} round={true} intent={Intent.NONE}>
@@ -49,20 +56,32 @@ export const ItemCodeAccessor = (row) =>
''
);
/**
* Quantity on hand cell.
*/
export const QuantityOnHandCell = ({ cell: { value } }) => {
return isNumber(value) ? (
<span className={'quantity_on_hand'}>{value}</span>
) : null;
};
/**
* Cost price cell.
*/
export const CostPriceCell = ({ cell: { value } }) => {
return !isBlank(value) ? <Money amount={value} currency={'USD'} /> : null;
};
/**
* Sell price cell.
*/
export const SellPriceCell = ({ cell: { value } }) => {
return !isBlank(value) ? <Money amount={value} currency={'USD'} /> : null;
};
/**
* Item type accessor.
*/
export const ItemTypeAccessor = (row) => {
return row.type ? (
<Tag minimal={true} round={true} intent={Intent.NONE}>
@@ -71,67 +90,104 @@ export const ItemTypeAccessor = (row) => {
) : null;
};
export const ItemsActionMenuList = ({
export const ActionsMenu = ({
row: { original },
payload: {
onEditItem,
onInactivateItem,
onActivateItem,
onMakeAdjustment,
onDeleteItem,
},
payload: { onDelete },
}) => {
const { formatMessage } = useIntl();
return (
<Menu>
<MenuItem
icon={<Icon icon="reader-18" />}
text={<T id={'view_details'} />}
text={formatMessage({ id: 'view_details' })}
/>
<MenuDivider />
<MenuItem
icon={<Icon icon="pen-18" />}
text={formatMessage({ id: 'edit_item' })}
onClick={safeCallback(onEditItem, original)}
/>
<If condition={original.active}>
<MenuItem
text={formatMessage({ id: 'inactivate_item' })}
icon={<Icon icon="pause-16" iconSize={16} />}
onClick={safeCallback(onInactivateItem, original)}
/>
</If>
<If condition={!original.active}>
<MenuItem
text={formatMessage({ id: 'activate_item' })}
icon={<Icon icon="play-16" iconSize={16} />}
onClick={safeCallback(onActivateItem, original)}
/>
</If>
<If condition={original.type === 'inventory'}>
<MenuItem
text={formatMessage({ id: 'make_adjustment' })}
onClick={safeCallback(onMakeAdjustment, original)}
/>
</If>
<MenuItem
text={formatMessage({ id: 'delete_item' })}
icon={<Icon icon="trash-16" iconSize={16} />}
onClick={safeCallback(onDeleteItem, original)}
text={formatMessage({ id: 'delete_adjustment' })}
intent={Intent.DANGER}
onClick={safeCallback(onDelete, original)}
icon={<Icon icon="trash-16" iconSize={16} />}
/>
</Menu>
);
};
export const ItemsActionsTableCell = (props) => {
return (
<Popover
position={Position.RIGHT_BOTTOM}
content={<ItemsActionMenuList {...props} />}
>
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
</Popover>
export const ActionsCell = (props) => {
return (<Popover
content={<ActionsMenu {...props} />}
position={Position.RIGHT_BOTTOM}
>
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
</Popover>
);
};
/**
* Retrieve inventory adjustments columns.
*/
export const useInventoryAdjustmentsColumns = () => {
const { formatMessage } = useIntl();
return React.useMemo(
() => [
{
id: 'date',
Header: formatMessage({ id: 'date' }),
accessor: (r) => moment(r.date).format('YYYY MMM DD'),
width: 115,
className: 'date',
},
{
id: 'type',
Header: formatMessage({ id: 'type' }),
accessor: TypeAccessor,
className: 'type',
width: 100,
},
{
id: 'reason',
Header: formatMessage({ id: 'reason' }),
accessor: 'reason',
className: 'reason',
width: 115,
},
{
id: 'reference_no',
Header: formatMessage({ id: 'reference_no' }),
accessor: 'reference_no',
className: 'reference_no',
width: 100,
},
{
id: 'publish',
Header: formatMessage({ id: 'status' }),
accessor: PublishAccessor,
width: 95,
className: 'publish',
},
{
id: 'description',
Header: formatMessage({ id: 'description' }),
accessor: 'description',
disableSorting: true,
width: 85,
className: 'description',
},
{
id: 'created_at',
Header: formatMessage({ id: 'created_at' }),
accessor: (r) => moment(r.created_at).format('YYYY MMM DD'),
width: 125,
className: 'created_at',
},
{
id: 'actions',
Header: '',
Cell: ActionsCell,
className: 'actions',
width: 50,
disableResizing: true,
},
],
[formatMessage],
);
};

View File

@@ -1,24 +1,9 @@
import { connect } from 'react-redux';
import {
submitInventoryAdjustment,
deleteInventoryAdjustment,
fetchInventoryAdjustmentsTable,
} from 'store/inventoryAdjustments/inventoryAdjustment.actions';
import t from 'store/types';
import { setInventoryAdjustmentsTableState } from 'store/inventoryAdjustments/inventoryAdjustment.actions';
const mapDispatchToProps = (dispatch) => ({
requestSubmitInventoryAdjustment: ({ form }) =>
dispatch(submitInventoryAdjustment({ form })),
requestFetchInventoryAdjustmentTable: (query = {}) =>
dispatch(fetchInventoryAdjustmentsTable({ query: { ...query } })),
requestDeleteInventoryAdjustment: (id) =>
dispatch(deleteInventoryAdjustment({ id })),
addInventoryAdjustmentTableQueries: (queries) =>
dispatch({
type: t.INVENTORY_ADJUSTMENTS_TABLE_QUERIES_ADD,
payload: { queries },
}),
setInventoryAdjustmentTableState: (queries) =>
dispatch(setInventoryAdjustmentsTableState(queries)),
});
export default connect(null, mapDispatchToProps);

View File

@@ -1,32 +1,15 @@
import { connect } from 'react-redux';
import {
getInvoiceTableQueryFactory,
getInventoryAdjustmentCurrentPageFactory,
getInventoryAdjustmentPaginationMetaFactory,
} from 'store/inventoryAdjustments/inventoryAdjustment.selector';
import { getInventroyAdjsTableStateFactory } from 'store/inventoryAdjustments/inventoryAdjustment.selector';
export default (mapState) => {
const getInventoryAdjustmentItems = getInventoryAdjustmentCurrentPageFactory();
const getInventoryAdjustmentTableQuery = getInvoiceTableQueryFactory();
const getInventoryAdjustmentsPaginationMeta = getInventoryAdjustmentPaginationMetaFactory();
const getInventoryAdjustmentTableState = getInventroyAdjsTableStateFactory();
const mapStateToProps = (state, props) => {
const query = getInventoryAdjustmentTableQuery(state, props);
const mapped = {
inventoryAdjustmentCurrentPage: getInventoryAdjustmentItems(
inventoryAdjustmentTableState: getInventoryAdjustmentTableState(
state,
props,
query,
),
inventoryAdjustmentItems: Object.values(state.inventoryAdjustments.items),
inventoryAdjustmentTableQuery: query,
inventoryAdjustmentsPagination: getInventoryAdjustmentsPaginationMeta(
state,
props,
query,
),
inventoryAdjustmentLoading: state.inventoryAdjustments.loading,
inventoryAdjustmentsSelectedRows: state.inventoryAdjustments.selectedRows,
};
return mapState ? mapState(mapped, state, props) : mapped;

View File

@@ -7,7 +7,7 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import ItemsCategoriesAlerts from './ItemsCategoriesAlerts';
import ItemsCategoryActionsBar from './ItemsCategoryActionsBar';
import { ItemsCategoriesProvider } from './ItemsCategoriesProvider';
import ItemCategoriesViewPage from './ItemCategoriesViewPage';
import ItemCategoriesTable from './ItemCategoriesTable';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import { compose } from 'utils';
@@ -22,6 +22,7 @@ const ItemCategoryList = ({
const { id } = useParams();
const { formatMessage } = useIntl();
// Changes the dashboard page title once the page mount.
useEffect(() => {
id
? changePageTitle(formatMessage({ id: 'edit_category_details' }))
@@ -33,7 +34,7 @@ const ItemCategoryList = ({
<ItemsCategoryActionsBar />
<DashboardPageContent>
<ItemCategoriesViewPage />
<ItemCategoriesTable />
</DashboardPageContent>
<ItemsCategoriesAlerts />
</ItemsCategoriesProvider>

View File

@@ -1,60 +1,52 @@
import React, { useMemo } from 'react';
import { useIntl } from 'react-intl';
import React from 'react';
import classNames from 'classnames';
import { TableActionsCell } from './components';
import { useItemsCategoriesTableColumns, ActionMenuList } from './components';
import DataTable from 'components/DataTable';
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
import { useItemsCategoriesContext } from './ItemsCategoriesProvider';
import { CLASSES } from 'common/classes';
import withAlertActions from 'containers/Alert/withAlertActions';
import withDialogActions from 'containers/Dialog/withDialogActions';
import { compose } from 'utils';
/**
* Items categories table.
*/
export default function ItemsCategoryTable({
function ItemsCategoryTable({
// #ownProps
tableProps,
// #withDialogActions
openDialog,
// #withAlertActions
openAlert
}) {
const { formatMessage } = useIntl();
// Items categories context.
const {
isItemsCategoriesFetching,
isCategoriesLoading,
isCategoriesFetching,
itemsCategories,
} = useItemsCategoriesContext();
// Table columns.
const columns = useMemo(
() => [
{
id: 'name',
Header: formatMessage({ id: 'category_name' }),
accessor: 'name',
width: 220,
},
{
id: 'description',
Header: formatMessage({ id: 'description' }),
accessor: 'description',
className: 'description',
width: 220,
},
{
id: 'count',
Header: formatMessage({ id: 'count' }),
accessor: 'count',
className: 'count',
width: 180,
},
{
id: 'actions',
Header: '',
Cell: TableActionsCell,
className: 'actions',
width: 50,
},
],
[formatMessage],
);
const columns = useItemsCategoriesTableColumns();
const handleSelectedRowsChange = (selectedRows) => {};
// Handle delete Item.
const handleDeleteCategory = ({ id }) => {
openAlert('item-category-delete', { itemCategoryId: id });
};
// Handle Edit item category.
const handleEditCategory = (category) => {
openDialog('item-category-form', { action: 'edit', id: category.id });
};
return (
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
@@ -62,14 +54,29 @@ export default function ItemsCategoryTable({
noInitialFetch={true}
columns={columns}
data={itemsCategories}
loading={isItemsCategoriesFetching}
loading={isCategoriesLoading}
headerLoading={isCategoriesLoading}
progressBarLoading={isCategoriesFetching}
manualSortBy={true}
expandable={true}
sticky={true}
selectionColumn={true}
TableLoadingRenderer={TableSkeletonRows}
noResults={'There is no items categories in table yet.'}
payload={{
onDeleteCategory: handleDeleteCategory,
onEditCategory: handleEditCategory
}}
ContextMenu={ActionMenuList}
{...tableProps}
/>
</div>
);
}
export default compose(
withDialogActions,
withAlertActions,
)(ItemsCategoryTable);

View File

@@ -1,47 +0,0 @@
import React from 'react';
import ItemCategoriesDataTable from './ItemCategoriesTable';
import withAlertActions from 'containers/Alert/withAlertActions';
import withDialogActions from 'containers/Dialog/withDialogActions';
import { compose } from 'utils';
/**
* Items categories view page.
*/
function ItemsCategoriesViewPage({
// #withAlertsActions
openAlert,
// #withDialogActions
openDialog,
}) {
// Handle selected rows change.
const handleSelectedRowsChange = (selectedRows) => {};
// Handle delete Item.
const handleDeleteCategory = ({ id }) => {
openAlert('item-category-delete', { itemCategoryId: id });
};
// Handle Edit item category.
const handleEditCategory = (category) => {
openDialog('item-category-form', { action: 'edit', id: category.id });
};
return (
<ItemCategoriesDataTable
tableProps={{
payload: {
onDeleteCategory: handleDeleteCategory,
onEditCategory: handleEditCategory,
},
}}
/>
);
}
export default compose(
withDialogActions,
withAlertActions,
)(ItemsCategoriesViewPage);

View File

@@ -10,13 +10,18 @@ const ItemsCategoriesContext = createContext();
function ItemsCategoriesProvider({ query, ...props }) {
const {
data: { itemsCategories, pagination },
isFetching: isItemsCategoriesFetching,
isFetching: isCategoriesFetching,
isLoading: isCategoriesLoading,
} = useItemsCategories();
const state = {
isItemsCategoriesFetching,
isCategoriesFetching,
isCategoriesLoading,
itemsCategories,
pagination,
query,
};
return (

View File

@@ -16,7 +16,7 @@ import { If, Icon } from 'components';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withItemCategories from './withItemCategories';
// import withItemCategories from './withItemCategories';
import withAlertActions from 'containers/Alert/withAlertActions';
import { compose } from 'utils';
@@ -26,7 +26,7 @@ import { compose } from 'utils';
*/
function ItemsCategoryActionsBar({
// #withItemCategories
itemCategoriesSelectedRows,
itemCategoriesSelectedRows = [],
// #withDialog
openDialog,
@@ -103,8 +103,8 @@ function ItemsCategoryActionsBar({
export default compose(
withDialogActions,
withItemCategories(({ itemCategoriesSelectedRows }) => ({
itemCategoriesSelectedRows,
})),
// withItemCategories(({ itemCategoriesSelectedRows }) => ({
// itemCategoriesSelectedRows,
// })),
withAlertActions,
)(ItemsCategoryActionsBar);

View File

@@ -52,3 +52,44 @@ export function TableActionsCell(props) {
</Popover>
);
}
/**
* Retrieve the items categories table columns.
*/
export function useItemsCategoriesTableColumns() {
const { formatMessage } = useIntl();
return React.useMemo(
() => [
{
id: 'name',
Header: formatMessage({ id: 'category_name' }),
accessor: 'name',
width: 220,
},
{
id: 'count',
Header: formatMessage({ id: 'count' }),
accessor: 'count',
className: 'count',
width: 180,
},
{
id: 'description',
Header: formatMessage({ id: 'description' }),
accessor: 'description',
className: 'description',
width: 220,
},
{
id: 'actions',
Header: '',
Cell: TableActionsCell,
className: 'actions',
width: 50,
},
],
[formatMessage],
);
}

View File

@@ -1,19 +1,16 @@
import { connect } from 'react-redux';
import { getItemsCategoriesListFactory } from 'store/itemCategories/ItemsCategories.selectors';
import { getResourceViews } from 'store/customViews/customViews.selectors';
import {
getItemsCategoriesTableStateFactory,
} from 'store/itemCategories/itemsCategories.selectors';
export default (mapState) => {
const getItemsCategoriesList = getItemsCategoriesListFactory();
const getItemsCategoriesTableState = getItemsCategoriesTableStateFactory();
const mapStateToProps = (state, props) => {
const mapped = {
categoriesList: getItemsCategoriesList(state, props),
itemCategoriesViews: getResourceViews(state, props, 'items_categories'),
categoriesTableLoading: state.itemCategories.loading,
itemCategoriesSelectedRows: state.itemCategories.selectedRows,
const mapped = {
itemsCategoriesTableState: getItemsCategoriesTableState(state, props),
};
return mapState ? mapState(mapped, state, props) : mapState;
};
return connect(mapStateToProps);
};

View File

@@ -1,38 +1,9 @@
import { connect } from 'react-redux';
import {
fetchItemCategories,
submitItemCategory,
deleteItemCategory,
editItemCategory,
deleteBulkItemCategories,
} from 'store/itemCategories/itemsCategory.actions';
import t from 'store/types';
import { setItemsCategoriesTableState } from 'store/itemCategories/itemsCategory.actions';
export const mapDispatchToProps = (dispatch) => ({
requestSubmitItemCategory: (form) => dispatch(submitItemCategory({ form })),
requestFetchItemCategories: (query) =>
dispatch(fetchItemCategories({ query })),
requestDeleteItemCategory: (id) => dispatch(deleteItemCategory(id)),
requestEditItemCategory: (id, form) => dispatch(editItemCategory(id, form)),
requestDeleteBulkItemCategories: (ids) =>
dispatch(deleteBulkItemCategories({ ids })),
changeItemCategoriesView: (id) =>
dispatch({
type: t.ITEM_CATEGORIES_SET_CURRENT_VIEW,
currentViewId: parseInt(id, 10),
}),
addItemCategoriesTableQueries: (queries) =>
dispatch({
type: t.ITEM_CATEGORIES_TABLE_QUERIES_ADD,
queries,
}),
setSelectedRowsCategories: (selectedRows) =>
dispatch({
type: t.ITEM_CATEGORY_SELECTED_ROW_SET,
payload: { selectedRows },
}),
setItemsCategoriesTableState: (state) =>
dispatch(setItemsCategoriesTableState(state)),
});
export default connect(null, mapDispatchToProps);

View File

@@ -1,5 +1,14 @@
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { defaultTo } from 'lodash';
import ApiService from 'services/ApiService';
import { transformPagination } from 'utils';
const invalidateQueries = (queryClient) => {
queryClient.invalidateQueries('INVENTORY_ADJUSTMENTS');
queryClient.invalidateQueries('ITEMS');
queryClient.invalidateQueries('ITEM');
};
/**
* Creates the inventory adjustment to the given item.
@@ -11,7 +20,7 @@ export function useCreateInventoryAdjustment(props) {
(values) => ApiService.post('inventory_adjustments/quick', values),
{
onSuccess: () => {
queryClient.invalidateQueries('INVENTORY_ADJUSTMENTS');
invalidateQueries(queryClient)
},
...props,
},
@@ -28,7 +37,7 @@ export function useDeleteInventoryAdjustment(props) {
(id) => ApiService.delete(`inventory_adjustments/${id}`),
{
onSuccess: () => {
queryClient.invalidateQueries('INVENTORY_ADJUSTMENTS');
invalidateQueries(queryClient)
},
...props
},
@@ -38,7 +47,7 @@ export function useDeleteInventoryAdjustment(props) {
const inventoryAdjustmentsTransformer = (response) => {
return {
transactions: response.data.inventoy_adjustments,
pagination: response.data.pagination,
pagination: transformPagination(response.data.pagination),
};
}
@@ -46,20 +55,22 @@ const inventoryAdjustmentsTransformer = (response) => {
* Retrieve inventory adjustment list with pagination meta.
*/
export function useInventoryAdjustments(query, props) {
return useQuery(
const states = useQuery(
['INVENTORY_ADJUSTMENTS', query],
() => ApiService.get('inventory_adjustments', { params: query })
.then(inventoryAdjustmentsTransformer),
{
initialData: {
transactions: [],
pagination: {
page: 1,
page_size: 12,
total: 0
},
},
...props,
},
props,
);
return {
...states,
data: defaultTo(states.data, {
transactions: [],
pagination: {
page: 1,
pageSize: 12,
total: 0,
pagesCount: 0,
}
})
}
}

View File

@@ -18,6 +18,7 @@ export function useCreateItem(props) {
return useMutation((values) => ApiService.post('items', values), {
onSuccess: () => {
queryClient.invalidateQueries('ITEMS');
queryClient.invalidateQueries('ITEMS_CATEGORIES');
},
...props,
});
@@ -33,6 +34,7 @@ export function useEditItem(props) {
onSuccess: () => {
queryClient.invalidateQueries('ITEMS');
queryClient.invalidateQueries('ITEM');
queryClient.invalidateQueries('ITEMS_CATEGORIES');
},
...props,
});
@@ -48,6 +50,7 @@ export function useDeleteItem(props) {
onSuccess: () => {
queryClient.invalidateQueries('ITEMS');
queryClient.invalidateQueries('ITEM');
queryClient.invalidateQueries('ITEMS_CATEGORIES');
},
...props,
});

View File

@@ -1,4 +1,5 @@
import { useQuery, useMutation, useQueryClient } from 'react-query';
import { defaultTo } from 'lodash';
import ApiService from 'services/ApiService';
/**
@@ -7,15 +8,12 @@ import ApiService from 'services/ApiService';
export function useCreateItemCategory(props) {
const queryClient = useQueryClient();
return useMutation(
(values) => ApiService.post('item_categories', values),
{
onSuccess: () => {
queryClient.invalidateQueries('ITEMS_CATEGORIES');
},
...props
}
);
return useMutation((values) => ApiService.post('item_categories', values), {
onSuccess: () => {
queryClient.invalidateQueries('ITEMS_CATEGORIES');
},
...props,
});
}
/**
@@ -29,9 +27,10 @@ export function useEditItemCategory(props) {
{
onSuccess: () => {
queryClient.invalidateQueries('ITEMS_CATEGORIES');
queryClient.invalidateQueries('ITEMS');
},
...props
}
...props,
},
);
}
@@ -41,14 +40,13 @@ export function useEditItemCategory(props) {
export function useDeleteItemCategory(props) {
const queryClient = useQueryClient();
return useMutation(
(id) => ApiService.delete(`item_categories/${id}`),
{
onSuccess: () => {
queryClient.invalidateQueries('ITEMS_CATEGORIES');
},
...props
});
return useMutation((id) => ApiService.delete(`item_categories/${id}`), {
onSuccess: () => {
queryClient.invalidateQueries('ITEMS_CATEGORIES');
queryClient.invalidateQueries('ITEMS');
},
...props,
});
}
// Transforms items categories.
@@ -63,18 +61,22 @@ const transformItemsCategories = (response) => {
* Retrieve the items categories.
*/
export function useItemsCategories(query, props) {
return useQuery(
const states = useQuery(
['ITEMS_CATEGORIES', query],
() => ApiService.get(`item_categories`, { params: query })
.then(transformItemsCategories),
{
initialData: {
itemsCategories: [],
pagination: {}
},
...props,
},
() =>
ApiService.get(`item_categories`, { params: query }).then(
transformItemsCategories,
),
props,
);
return {
...states,
data: defaultTo(states.data, {
itemsCategories: [],
pagination: {},
}),
};
}
/**
@@ -82,13 +84,15 @@ export function useItemsCategories(query, props) {
* @param {number} id - Item category.
*/
export function useItemCategory(id, props) {
return useQuery(
const states = useQuery(
['ITEMS_CATEGORY', id],
() => ApiService.get(`item_categories/${id}`)
.then(res => res.data.category),
{
initialData: {},
...props,
},
() =>
ApiService.get(`item_categories/${id}`).then((res) => res.data.category),
props,
);
}
return {
...states,
data: defaultTo(states.data, {}),
};
}

View File

@@ -1,87 +1,11 @@
import ApiService from 'services/ApiService';
import t from 'store/types';
export const submitInventoryAdjustment = ({ form }) => {
return (dispatch) =>
new Promise((resolve, reject) => {
ApiService.post('inventory_adjustments/quick', form)
.then((response) => {
resolve(response);
})
.catch((error) => {
const { response } = error;
const { data } = response;
reject(data?.errors);
});
});
};
export const deleteInventoryAdjustment = ({ id }) => {
return (dispatch) =>
new Promise((resolve, reject) => {
ApiService.delete(`inventory_adjustments/${id}`)
.then((response) => {
dispatch({
type: t.INVENTORY_ADJUSTMENT_DELETE,
payload: { id },
});
resolve(response);
})
.catch((error) => {
reject(error.response.data.errors || []);
});
});
};
export const fetchInventoryAdjustmentsTable = ({ query } = {}) => {
return (dispatch, getState) =>
new Promise((resolve, reject) => {
const pageQuery = getState().inventoryAdjustments.tableQuery;
dispatch({
type: t.INVENTORY_ADJUSTMENTS_LOADING,
payload: {
loading: true,
},
});
ApiService.get('inventory_adjustments', {
params: { ...pageQuery, ...query },
})
.then((response) => {
dispatch({
type: t.INVENTORY_ADJUSTMENTS_PAGE_SET,
payload: {
inventory_adjustments: response.data.inventoy_adjustments,
pagination: response.data.pagination,
customViewId:
response.data?.filter_meta?.view?.custom_view_id || -1,
},
});
dispatch({
type: t.INVENTORY_ADJUSTMENT_ITEMS_SET,
payload: {
inventory_adjustment: response.data.inventoy_adjustments,
},
});
dispatch({
type: t.INVENTORY_ADJUSTMENTS_PAGINATION_SET,
payload: {
pagination: response.data.pagination,
customViewId:
response.data?.filter_meta?.view?.custom_view_id || -1,
},
});
dispatch({
type: t.INVENTORY_ADJUSTMENTS_LOADING,
payload: {
loading: false,
},
});
resolve(response);
})
.catch((error) => {
reject(error);
});
});
/**
* Sets the inventory adjustments table state.
*/
export const setInventoryAdjustmentsTableState = (queries) => {
return {
type: t.INVENTORY_ADJUSTMENTS_TABLE_STATE_SET,
payload: { queries },
};
};

View File

@@ -1,73 +1,17 @@
import { createReducer } from '@reduxjs/toolkit';
import {
viewPaginationSetReducer,
createTableQueryReducers,
} from 'store/journalNumber.reducer';
import t from 'store/types';
createTableStateReducers,
} from 'store/tableState.reducer';
const initialState = {
items: {},
views: {},
loading: false,
currentViewId: -1,
tableQuery: {
page_size: 12,
page: 1,
tableState: {
pageSize: 12,
pageIndex: 0,
sortBy: [],
},
selectedRows: [],
};
export default createReducer(initialState, {
[t.INVENTORY_ADJUSTMENTS_LOADING]: (state, action) => {
const { loading } = action.payload;
state.loading = loading;
},
[t.INVENTORY_ADJUSTMENT_DELETE]: (state, action) => {
const { id } = action.payload;
if (typeof state.items[id] !== 'undefined') {
delete state.items[id];
}
},
[t.INVENTORY_ADJUSTMENTS_PAGE_SET]: (state, action) => {
const { customViewId, inventory_adjustments, pagination } = action.payload;
const viewId = customViewId || -1;
const view = state.views[viewId] || {};
state.views[viewId] = {
...view,
pages: {
...(state.views?.[viewId]?.pages || {}),
[pagination.page]: {
ids: inventory_adjustments.map((i) => i.id),
},
},
};
},
[t.INVENTORY_ADJUSTMENT_ITEMS_SET]: (state, action) => {
const { inventory_adjustment } = action.payload;
const _inventory_adjustment = {};
inventory_adjustment.forEach((_inventory) => {
_inventory_adjustment[_inventory.id] = {
..._inventory,
};
});
state.items = {
...state.items,
..._inventory_adjustment,
};
},
[t.INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW]: (state, action) => {
state.currentViewId = action.currentViewId;
},
[t.INVENTORY_ADJUSTMENTS_SELECTED_ROW_SET]: (state, action) => {
const { selectedRows } = action.payload;
state.selectedRows = selectedRows;
},
...viewPaginationSetReducer(t.INVENTORY_ADJUSTMENTS_PAGINATION_SET),
...createTableQueryReducers('INVENTORY_ADJUSTMENTS'),
...createTableStateReducers('INVENTORY_ADJUSTMENTS'),
});

View File

@@ -1,36 +1,18 @@
import { createSelector } from '@reduxjs/toolkit';
import {
pickItemsFromIds,
paginationLocationQuery,
defaultPaginationMeta,
} from 'store/selectors';
const inventoryAdjustmentTableQuery = (state) =>
state.inventoryAdjustments.tableQuery;
const inventoryAdjustmentTableState = (state) =>
state.inventoryAdjustments.tableState;
const inventoryAdjustmentsPaginationSelector = (state, props) => {
const viewId = state.inventoryAdjustments.currentViewId;
return state.inventoryAdjustments.views?.[viewId];
};
const inventoryAdjustmentItemsSelector = (state) =>
state.inventoryAdjustments.items;
const inventoryAdjustmentCurrentPageSelector = (state, props) => {
const currentViewId = state.inventoryAdjustments.currentViewId;
const currentView = state.inventoryAdjustments.views?.[currentViewId];
const currentPageId = currentView?.paginationMeta?.page;
return currentView?.pages?.[currentPageId];
};
const getinventoryAdjustmentCurrentViewIdSelector = (state) =>
state.inventoryAdjustments.currentViewId;
export const getInvoiceTableQueryFactory = () =>
/**
* Retrieve the inventory adjustments table state.
*/
export const getInventroyAdjsTableStateFactory = () =>
createSelector(
paginationLocationQuery,
inventoryAdjustmentTableQuery,
inventoryAdjustmentTableState,
(locationQuery, tableQuery) => {
return {
...locationQuery,
@@ -38,22 +20,3 @@ export const getInvoiceTableQueryFactory = () =>
};
},
);
export const getInventoryAdjustmentCurrentPageFactory = () =>
createSelector(
inventoryAdjustmentCurrentPageSelector,
inventoryAdjustmentItemsSelector,
(currentPage, items) => {
return typeof currentPage === 'object'
? pickItemsFromIds(items, currentPage.ids) || []
: [];
},
);
export const getInventoryAdjustmentPaginationMetaFactory = () =>
createSelector(inventoryAdjustmentsPaginationSelector, (Page) => {
return {
...defaultPaginationMeta(),
...(Page?.paginationMeta || {}),
};
});

View File

@@ -1,15 +1,4 @@
export default {
INVENTORY_ADJUSTMENT_ITEMS_SET: 'INVENTORY_ADJUSTMENT_ITEMS_SET',
INVENTORY_ADJUSTMENT_DELETE: 'INVENTORY_ADJUSTMENT_DELETE',
INVENTORY_ADJUSTMENTS_LOADING: 'INVENTORY_ADJUSTMENTS_LOADING',
INVENTORY_ADJUSTMENTS_PAGE_SET: 'INVENTORY_ADJUSTMENTS_PAGE_SET',
INVENTORY_ADJUSTMENTS_PAGINATION_SET: 'INVENTORY_ADJUSTMENTS_PAGINATION_SET',
INVENTORY_ADJUSTMENTS_TABLE_QUERIES_ADD:
'INVENTORY_ADJUSTMENTS/TABLE_QUERIES_ADD',
INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW:
'INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW',
INVENTORY_ADJUSTMENTS_SELECTED_ROW_SET:
'INVENTORY_ADJUSTMENTS_SELECTED_ROW_SET',
};
INVENTORY_ADJUSTMENTS_TABLE_STATE_SET: 'INVENTORY_ADJUSTMENTS/TABLE_STATE_SET',
};

View File

@@ -1,18 +1,19 @@
import { createSelector } from 'reselect';
import { getItemById } from 'store/selectors';
import { paginationLocationQuery } from 'store/selectors';
import { createDeepEqualSelector } from 'utils';
const itemsCateogoriesDataSelector = (state) => state.itemCategories.categories;
const itemCategoryIdFromProps = (state, props) => props.itemCategoryId;
// Items categories table state.
const itemsCategoriesTableStateSelector = (state) =>
state.itemsCategories.tableState;
export const getItemsCategoriesListFactory = () =>
createSelector(itemsCateogoriesDataSelector, (itemsCategories) => {
return Object.values(itemsCategories);
});
export const getItemCategoryByIdFactory = () => createSelector(
itemsCateogoriesDataSelector,
itemCategoryIdFromProps,
(itemsCategories, itemCategoryid) => {
return getItemById(itemsCategories, itemCategoryid);
},
);
// Get items categories table state marged with location query.
export const getItemsCategoriesTableStateFactory = () =>
createDeepEqualSelector(
paginationLocationQuery,
itemsCategoriesTableStateSelector,
(locationQuery, tableState) => {
return {
...locationQuery,
...tableState,
};
},
);

View File

@@ -1,102 +1,11 @@
import ApiService from 'services/ApiService';
import t from 'store/types';
export const submitItemCategory = ({ form }) => {
return (dispatch) =>
new Promise((resolve, reject) => {
ApiService.post('item_categories', form)
.then((response) => {
resolve(response);
})
.catch((error) => {
const { response } = error;
const { data } = response;
reject(data?.errors);
});
});
};
export const fetchItemCategories = ({ query }) => {
return (dispatch, getState) =>
new Promise((resolve, reject) => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
dispatch({
type: t.ITEM_CATEGORIES_TABLE_LOADING,
payload: {
loading: true,
},
});
ApiService.get('item_categories', { params: { ...query } })
.then((response) => {
dispatch({
type: t.ITEMS_CATEGORY_LIST_SET,
categories: response.data.item_categories,
});
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
dispatch({
type: t.ITEM_CATEGORIES_TABLE_LOADING,
payload: {
loading: false,
},
});
resolve(response);
})
.catch((error) => {
reject(error);
});
});
};
export const editItemCategory = (id, form) => {
return (dispatch) =>
new Promise((resolve, reject) => {
ApiService.post(`item_categories/${id}`, form)
.then((response) => {
resolve(response);
})
.catch((error) => {
const { response } = error;
const { data } = response;
reject(data?.errors);
});
});
};
export const deleteItemCategory = (id) => {
return (dispatch) =>
new Promise((resolve, reject) => {
ApiService.delete(`item_categories/${id}`)
.then((response) => {
dispatch({
type: t.CATEGORY_DELETE,
payload: { id },
});
resolve(response);
})
.catch((error) => {
reject(error);
});
});
};
export const deleteBulkItemCategories = ({ ids }) => {
return (dispatch) =>
new Promise((resolve, reject) => {
ApiService.delete(`item_categories`, { params: { ids } })
.then((response) => {
dispatch({
type: t.ITEM_CATEGORIES_BULK_DELETE,
payload: { ids },
});
resolve(response);
})
.catch((error) => {
reject(error);
});
});
/**
* Sets the items categories table state.
*/
export const setItemsCategoriesTableState = (queries) => {
return {
type: t.ITEMS_CATEGORIES_TABLE_STATE_SET,
payload: { queries },
};
};

View File

@@ -1,58 +1,13 @@
import t from 'store/types';
import { createReducer } from '@reduxjs/toolkit';
import {
createTableStateReducers,
} from 'store/tableState.reducer';
// Initial state.
const initialState = {
categories: {},
loading: false,
selectedRows: [],
tableState: {},
};
export default createReducer(initialState, {
[t.ITEMS_CATEGORY_LIST_SET]: (state, action) => {
const _categories = {};
action.categories.forEach((category) => {
_categories[category.id] = category;
});
state.categories = {
...state.categories,
..._categories,
};
},
[t.ITEM_CATEGORIES_TABLE_SET]: (state, action) => {},
[t.CATEGORY_DELETE]: (state, action) => {
const { id } = action.payload;
if (typeof state.categories[id] !== 'undefined') {
delete state.categories[id];
}
},
[t.ITEM_CATEGORIES_TABLE_LOADING]: (state, action) => {
const { loading } = action.payload;
state.loading = !!loading;
},
[t.ITEM_CATEGORIES_BULK_DELETE]: (state, action) => {
const { ids } = action.payload;
const categories = { ...state.categories };
ids.forEach((id) => {
if (typeof categories[id] !== 'undefined') {
delete categories[id];
}
});
state.categories = categories;
},
[t.ITEM_CATEGORY_SELECTED_ROW_SET]: (state, action) => {
const { selectedRows } = action.payload;
state.selectedRows = selectedRows;
},
...createTableStateReducers('ITEMS_CATEGORIES'),
});
export const getCategoryId = (state, id) => {
return state.itemCategories.categories[id] || {};
};

View File

@@ -1,10 +1,3 @@
export default {
ITEMS_CATEGORY_LIST_SET: 'ITEMS_CATEGORY_LIST_SET',
ITEMS_CATEGORY_DATA_TABLE: 'ITEMS_CATEGORY_DATA_TABLE',
CATEGORY_DELETE: 'CATEGORY_DELETE',
ITEM_CATEGORIES_TABLE_LOADING: 'ITEM_CATEGORIES_TABLE_LOADING',
ITEM_CATEGORIES_BULK_DELETE: 'ITEM_CATEGORIES_BULK_DELETE',
ITEM_CATEGORIES_TABLE_QUERIES_ADD: 'ITEM_CATEGORIES_TABLE_QUERIES_ADD',
ITEM_CATEGORIES_SET_CURRENT_VIEW: 'ITEM_CATEGORIES_SET_CURRENT_VIEW',
ITEM_CATEGORY_SELECTED_ROW_SET: 'ITEM_CATEGORY_SELECTED_ROW_SET',
ITEMS_CATEGORIES_TABLE_STATE_SET: 'ITEMS_CATEGORIES/TABLE_STATE_SET',
};

View File

@@ -11,7 +11,7 @@ import expenses from './expenses/expenses.reducer';
import currencies from './currencies/currencies.reducer';
import resources from './resources/resources.reducer';
import financialStatements from './financialStatement/financialStatements.reducer';
import itemCategories from './itemCategories/itemsCategory.reducer';
import itemsCategories from './itemCategories/itemsCategory.reducer';
import settings from './settings/settings.reducer';
import manualJournals from './manualJournals/manualJournals.reducers';
import globalSearch from './search/search.reducer';
@@ -45,7 +45,7 @@ export default combineReducers({
resources,
financialStatements,
items,
itemCategories,
itemsCategories,
settings,
globalSearch,
exchangeRates,

View File

@@ -531,8 +531,10 @@ export function globalTableStateToTable(globalState) {
* Transformes the pagination meta repsonse.
*/
export function transformPagination(pagination) {
const transformed = transformResponse(pagination);
return {
...pagination,
pagesCount: getPagesCountFromPaginationMeta(pagination),
}
...transformed,
pagesCount: getPagesCountFromPaginationMeta(transformed),
};
}

View File

@@ -1,6 +1,6 @@
import { Inject, Service } from 'typedi';
import { Router, Request, Response, NextFunction } from 'express';
import { check, param } from 'express-validator';
import { check, query, param } from 'express-validator';
import { ServiceError } from 'exceptions';
import BaseController from '../BaseController';
import InventoryAdjustmentService from 'services/Inventory/InventoryAdjustmentService';
@@ -39,12 +39,28 @@ export default class InventoryAdjustmentsController extends BaseController {
);
router.get(
'/',
[...this.validateListQuerySchema],
this.validationResult,
this.asyncMiddleware(this.getInventoryAdjustments.bind(this)),
this.handleServiceErrors
);
return router;
}
/**
* Validate list query schema
*/
get validateListQuerySchema() {
return [
query('column_sort_by').optional().trim().escape(),
query('sort_order').optional().isIn(['desc', 'asc']),
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
];
}
/**
* Quick inventory adjustment validation schema.
*/