diff --git a/client/src/components/DialogsContainer.js b/client/src/components/DialogsContainer.js
index ededd0cd0..1259ebf89 100644
--- a/client/src/components/DialogsContainer.js
+++ b/client/src/components/DialogsContainer.js
@@ -1,14 +1,14 @@
import React from 'react';
import AccountFormDialog from 'containers/Dashboard/Dialogs/AccountFormDialog';
import UserFormDialog from 'containers/Dashboard/Dialogs/UserFormDialog';
-import ItemFromDialog from 'containers/Dashboard/Dialogs/ItemFromDialog';
+import ItemFCategoryDialog from 'containers/Dashboard/Dialogs/ItemCategoryDialog';
export default function DialogsContainer() {
return (
+
-
);
}
diff --git a/client/src/components/Items/ItemsCategoryList.js b/client/src/components/Items/ItemsCategoryList.js
new file mode 100644
index 000000000..33f1ba7b6
--- /dev/null
+++ b/client/src/components/Items/ItemsCategoryList.js
@@ -0,0 +1,85 @@
+import React, { useEffect, useCallback, useState, useMemo } from 'react';
+import Icon from 'components/Icon';
+import ItemsCategoryConnect from 'connectors/ItemsCategory.connect';
+import DialogConnect from 'connectors/Dialog.connector';
+import LoadingIndicator from 'components/LoadingIndicator';
+import { compose } from 'utils';
+import DataTable from 'components/DataTable';
+import { Button, Popover, Menu, MenuItem, Position } from '@blueprintjs/core';
+
+const ItemsCategoryList = ({
+ categories,
+ onFetchData,
+ onDeleteCategory,
+ onEditCategory,
+ openDialog
+}) => {
+ const handelEditCategory = category => () => {
+ openDialog('item-form', { action: 'edit', id: category.id });
+ onEditCategory(category.id);
+ };
+
+ const handleDeleteCategory = category => () => {
+ onDeleteCategory(category);
+ };
+
+ const actionMenuList = category => (
+
+ );
+
+ const columns = useMemo(
+ () => [
+ {
+ id: 'name',
+ Header: 'Category Name',
+ accessor: 'name'
+ },
+ {
+ id: 'description',
+ Header: 'Description',
+ accessor: 'description'
+ },
+
+ {
+ id: 'actions',
+ Header: '',
+ Cell: ({ cell }) => (
+
+ } />
+
+ ),
+ className: 'actions',
+ width: 50
+ // canResize: false
+ }
+ ],
+ []
+ );
+
+ const handelFetchData = useCallback(() => {
+ onFetchData && onFetchData();
+ }, []);
+
+ return (
+
+
+
+ );
+};
+
+export default compose(DialogConnect, ItemsCategoryConnect)(ItemsCategoryList);
diff --git a/client/src/config/sidebarMenu.js b/client/src/config/sidebarMenu.js
index c1a39b500..522fa6077 100644
--- a/client/src/config/sidebarMenu.js
+++ b/client/src/config/sidebarMenu.js
@@ -17,6 +17,10 @@ export default [
iconSize: 20,
text: 'Items',
children: [
+ {
+ text: 'Category List',
+ href: '/dashboard/items/ItemCategoriesList'
+ },
{
text: 'Items List',
href: '/dashboard/items/list'
@@ -24,10 +28,6 @@ export default [
{
text: 'New Item',
href: '/dashboard/items/new'
- },
- {
- text: 'Category List',
- href: '/dashboard/items/category'
}
]
},
diff --git a/client/src/connectors/ItemsCategory.connect.js b/client/src/connectors/ItemsCategory.connect.js
new file mode 100644
index 000000000..1762b3f3f
--- /dev/null
+++ b/client/src/connectors/ItemsCategory.connect.js
@@ -0,0 +1,31 @@
+import { connect } from 'react-redux';
+import {
+ fetchItemCategories,
+ submitItemCategory,
+ deleteItemCategory,
+ editItemCategory
+} from 'store/itemCategories/itemsCategory.actions';
+import { getDialogPayload } from 'store/dashboard/dashboard.reducer';
+import { getCategoryId } from 'store/itemCategories/itemsCategory.reducer';
+
+export const mapStateToProps = (state, props) => {
+ const dialogPayload = getDialogPayload(state, 'item-form');
+ return {
+ categories: state.itemCategories.categories,
+ name: 'item-form',
+ payload: { action: 'new', id: null },
+ editItemCategory:
+ dialogPayload && dialogPayload.action === 'edit'
+ ? state.itemCategories.categories[dialogPayload.id]
+ : {},
+ getCategoryId: id => getCategoryId(state, id)
+ };
+};
+export const mapDispatchToProps = dispatch => ({
+ requestSubmitItemCategory: form => dispatch(submitItemCategory({ form })),
+ requestFetchItemCategories: () => dispatch(fetchItemCategories()),
+ requestDeleteItemCategory: id => dispatch(deleteItemCategory(id)),
+ requestEditItemCategory: (id, form) => dispatch(editItemCategory(id, form))
+});
+
+export default connect(mapStateToProps, mapDispatchToProps);
diff --git a/client/src/containers/Dashboard/Dialogs/ItemCategoryDialog.js b/client/src/containers/Dashboard/Dialogs/ItemCategoryDialog.js
new file mode 100644
index 000000000..53ced0aa5
--- /dev/null
+++ b/client/src/containers/Dashboard/Dialogs/ItemCategoryDialog.js
@@ -0,0 +1,205 @@
+import React, { useState } from 'react';
+import {
+ Button,
+ Classes,
+ FormGroup,
+ InputGroup,
+ Intent,
+ TextArea,
+ MenuItem
+} from '@blueprintjs/core';
+import { Select } from '@blueprintjs/select';
+import { omit, pick } from 'lodash';
+import * as Yup from 'yup';
+import { useIntl } from 'react-intl';
+import { useFormik } from 'formik';
+import { compose } from 'utils';
+import Dialog from 'components/Dialog';
+import useAsync from 'hooks/async';
+import AppToaster from 'components/AppToaster';
+import DialogConnect from 'connectors/Dialog.connector';
+import DialogReduxConnect from 'components/DialogReduxConnect';
+import ItemsCategoryConnect from 'connectors/ItemsCategory.connect';
+
+function ItemCategoryDialog({
+ name,
+ payload,
+ isOpen,
+ openDialog,
+ closeDialog,
+ categories,
+ requestSubmitItemCategory,
+ requestFetchItemCategories,
+ requestEditItemCategory,
+ editItemCategory
+}) {
+ const [state, setState] = useState({
+ selectedParentCategory: null
+ });
+ const intl = useIntl();
+ const ValidationSchema = Yup.object().shape({
+ name: Yup.string().required(intl.formatMessage({ id: 'required' })),
+ parent_category_id: Yup.string().nullable(),
+ description: Yup.string().trim()
+ });
+
+ const initialValues = {
+ name: '',
+ description: '',
+ parent_category_id: null
+ };
+ //Formik
+ const formik = useFormik({
+ enableReinitialize: true,
+ initialValues: {
+ ...(payload.action === 'edit' &&
+ pick(editItemCategory, Object.keys(initialValues)))
+ },
+ validationSchema: ValidationSchema,
+ onSubmit: values => {
+ if (payload.action === 'edit') {
+ requestEditItemCategory(payload.id, values).then(response => {
+ closeDialog(name);
+ AppToaster.show({
+ message: 'the_category_has_been_edited'
+ });
+ });
+ } else {
+ requestSubmitItemCategory(values)
+ .then(response => {
+ closeDialog(name);
+ AppToaster.show({
+ message: 'the_category_has_been_submit'
+ });
+ })
+ .catch(error => {
+ alert(error.message);
+ });
+ }
+ }
+ });
+
+ const filterItemCategory = (query, category, _index, exactMatch) => {
+ const normalizedTitle = category.name.toLowerCase();
+ const normalizedQuery = query.toLowerCase();
+
+ if (exactMatch) {
+ return normalizedTitle === normalizedQuery;
+ } else {
+ return normalizedTitle.indexOf(normalizedQuery) >= 0;
+ }
+ };
+
+ const parentCategoryItem = (category, { handleClick, modifiers, query }) => {
+ return (
+
+ );
+ };
+ const handleClose = () => {
+ closeDialog(name);
+ };
+
+ const fetchHook = useAsync(async () => {
+ await Promise.all([requestFetchItemCategories()]);
+ }, false);
+
+ const onDialogOpening = () => {
+ fetchHook.execute();
+ };
+
+ const onChangeParentCategory = parentCategory => {
+ setState({ ...state, selectedParentCategory: parentCategory.name });
+ formik.setFieldValue('parent_category_id', parentCategory.id);
+ };
+
+ const onDialogClosed = () => {
+ formik.resetForm();
+ closeDialog(name);
+ };
+
+ return (
+
+ );
+}
+
+export default compose(
+ ItemsCategoryConnect,
+ DialogConnect,
+ DialogReduxConnect
+)(ItemCategoryDialog);
diff --git a/client/src/containers/Dashboard/Items/ItemsActionsBar.js b/client/src/containers/Dashboard/Items/ItemsActionsBar.js
index c21c6439d..8a615215b 100644
--- a/client/src/containers/Dashboard/Items/ItemsActionsBar.js
+++ b/client/src/containers/Dashboard/Items/ItemsActionsBar.js
@@ -1,5 +1,5 @@
-import React, {useMemo} from 'react';
-import {useRouteMatch, useHistory} from 'react-router-dom'
+import React, { useMemo } from 'react';
+import { useRouteMatch, useHistory } from 'react-router-dom';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import { compose } from 'utils';
@@ -13,38 +13,50 @@ import {
Position,
Button,
Classes,
- Intent,
+ Intent
} from '@blueprintjs/core';
import classNames from 'classnames';
import Icon from 'components/Icon';
import DashboardConnect from 'connectors/Dashboard.connector';
-import ResourceConnect from 'connectors/Resource.connector'
+import ResourceConnect from 'connectors/Resource.connector';
import FilterDropdown from 'components/FilterDropdown';
import ItemsConnect from 'connectors/Items.connect';
+import DialogConnect from 'connectors/Dialog.connector';
const ItemsActionsBar = ({
+ openDialog,
getResourceFields,
getResourceViews,
views,
onFilterChange,
- bulkSelected,
+ bulkSelected
}) => {
- const {path} = useRouteMatch();
+ const { path } = useRouteMatch();
const history = useHistory();
- const viewsMenuItems = views.map((view) => {
- return ();
+ const viewsMenuItems = views.map(view => {
+ return (
+
+ );
});
- const onClickNewItem = () => { history.push('/dashboard/items/new'); };
+ const onClickNewItem = () => {
+ history.push('/dashboard/items/new');
+ };
const itemsFields = getResourceFields('items');
const filterDropdown = FilterDropdown({
fields: itemsFields,
- onFilterChange,
+ onFilterChange
});
- const hasBulkActionsSelected = useMemo(() =>
- !!Object.keys(bulkSelected).length, [bulkSelected]);
+ const hasBulkActionsSelected = useMemo(
+ () => !!Object.keys(bulkSelected).length,
+ [bulkSelected]
+ );
+
+ const onClickNewCategory = () => {
+ openDialog('item-form', {});
+ };
return (
@@ -53,13 +65,14 @@ const ItemsActionsBar = ({
content={}
minimal={true}
interactionKind={PopoverInteractionKind.HOVER}
- position={Position.BOTTOM_LEFT}>
-
+ position={Position.BOTTOM_LEFT}
+ >
}
- text="Table Views"
- rightIcon={'caret-down'} />
+ icon={}
+ text='Table Views'
+ rightIcon={'caret-down'}
+ />
@@ -67,26 +80,36 @@ const ItemsActionsBar = ({
-
+ position={Position.BOTTOM_LEFT}
+ >
} />
+ text='Filter'
+ icon={}
+ />
}
- text="New Item"
- onClick={onClickNewItem} />
+ icon={}
+ text='New Item'
+ onClick={onClickNewItem}
+ />
+ }
+ text='New Category'
+ onClick={onClickNewCategory}
+ />
{hasBulkActionsSelected && (
}
- text="Delete" />)}
+ icon={}
+ text='Delete'
+ />
+ )}