diff --git a/client/src/components/DialogsContainer.js b/client/src/components/DialogsContainer.js index 7528e25cd..ededd0cd0 100644 --- a/client/src/components/DialogsContainer.js +++ b/client/src/components/DialogsContainer.js @@ -1,12 +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'; export default function DialogsContainer() { return ( - {/* */} + + ); -} \ No newline at end of file +} diff --git a/client/src/components/Items/categoryList.js b/client/src/components/Items/categoryList.js new file mode 100644 index 000000000..5a7471f12 --- /dev/null +++ b/client/src/components/Items/categoryList.js @@ -0,0 +1,60 @@ +import React, { useMemo } from 'react'; +import { + Button, + Popover, + Menu, + MenuItem, + MenuDivider, + Position, + Checkbox +} from '@blueprintjs/core'; +import { + GridComponent, + ColumnsDirective, + ColumnDirective, + Inject, + Sort +} from '@syncfusion/ej2-react-grids'; +import LoadingIndicator from 'components/LoadingIndicator'; +import DashboardConnect from 'connectors/Dashboard.connector'; +import ItemFormDialogConnect from 'connectors/ItemFormDialog.connect'; +import Icon from 'components/Icon'; +import { useParams } from 'react-router-dom'; +import { handleBooleanChange, compose } from 'utils'; +import DataTable from 'components/DataTable'; +const categoryList = ({ categories }) => { + const columns = [ + { + field: 'name', + headerText: 'Name' + }, + { + field: 'description', + headerText: 'Description' + } + ]; + return ( + + + + + {/* {columns.map(column => { + return ( + + ); + })} */} + + + + ); +}; + +export default compose(DashboardConnect, ItemFormDialogConnect)(categoryList); diff --git a/client/src/config/sidebarMenu.js b/client/src/config/sidebarMenu.js index f40892cf9..c1a39b500 100644 --- a/client/src/config/sidebarMenu.js +++ b/client/src/config/sidebarMenu.js @@ -19,16 +19,20 @@ export default [ children: [ { text: 'Items List', - href: '/dashboard/items/list', + href: '/dashboard/items/list' }, { text: 'New Item', - href: '/dashboard/items/new', + href: '/dashboard/items/new' }, + { + text: 'Category List', + href: '/dashboard/items/category' + } ] }, { - divider: true, + divider: true }, { icon: 'balance-scale', @@ -37,29 +41,25 @@ export default [ children: [ { text: 'Accounts Chart', - href: '/dashboard/accounts', + href: '/dashboard/accounts' }, { text: 'Make Journal', href: '/dashboard/accounting/make-journal-entry' - }, + } ] }, { icon: 'university', iconSize: 20, text: 'Banking', - children: [ - - ] + children: [] }, { icon: 'shopping-cart', iconSize: 20, text: 'Sales', - children: [ - - ] + children: [] }, { icon: 'balance-scale', @@ -81,24 +81,24 @@ export default [ children: [ { text: 'Balance Sheet', - href: '/dashboard/accounting/balance-sheet', + href: '/dashboard/accounting/balance-sheet' }, { text: 'Trial Balance Sheet', - href: '/dashboard/accounting/trial-balance-sheet', + href: '/dashboard/accounting/trial-balance-sheet' }, { text: 'Journal', - href: '/dashboard/accounting/journal-sheet', + href: '/dashboard/accounting/journal-sheet' }, { text: 'General Ledger', - href: '/dashboard/accounting/general-ledger', + href: '/dashboard/accounting/general-ledger' }, { text: 'Profit Loss Sheet', - href: '/dashboard/accounting/profit-loss-sheet', - }, + href: '/dashboard/accounting/profit-loss-sheet' + } ] }, { @@ -108,12 +108,12 @@ export default [ children: [ { text: 'Expenses List', - href: '/dashboard/expenses', + href: '/dashboard/expenses' }, { text: 'New Expenses', - href: '/dashboard/expenses/new', - }, + href: '/dashboard/expenses/new' + } ] }, { diff --git a/client/src/connectors/ItemFormDialog.connect.js b/client/src/connectors/ItemFormDialog.connect.js new file mode 100644 index 000000000..14cf851bf --- /dev/null +++ b/client/src/connectors/ItemFormDialog.connect.js @@ -0,0 +1,24 @@ +//FIXME: FIX Later Need More Work + +import { connect } from 'react-redux'; +import { + submitItemCategory, + submitCategory, + fetchCategory +} from 'store/itemCategories/itemsCategory.actions'; + +export const mapStateToProps = (state, props) => { + return { + category: state.category, + name: 'item-form', + payload: { action: 'new', id: null } + }; +}; + +export const mapDispatchToProps = dispatch => ({ + submitItemCategory: form => dispatch(submitItemCategory({ form })), + submitCategory: form => dispatch(submitCategory({ form })), + fetchCategory: () => dispatch(fetchCategory()) +}); + +export default connect(mapStateToProps, mapDispatchToProps); diff --git a/client/src/containers/Dashboard/Dialogs/ItemFromDialog.js b/client/src/containers/Dashboard/Dialogs/ItemFromDialog.js new file mode 100644 index 000000000..e7b6c28c3 --- /dev/null +++ b/client/src/containers/Dashboard/Dialogs/ItemFromDialog.js @@ -0,0 +1,130 @@ +import React, { useState } from 'react'; +import { + Button, + Classes, + FormGroup, + InputGroup, + Intent, + TextArea +} from '@blueprintjs/core'; +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 ItemFormDialogConnect from 'connectors/ItemFormDialog.connect'; + +function ItemFromDialog({ + name, + payload, + isOpen, + submitItemCategory, + fetchCategory, + openDialog, + closeDialog +}) { + const [state, setState] = useState({}); + const intl = useIntl(); + const ValidationSchema = Yup.object().shape({ + name: Yup.string().required(intl.formatMessage({ id: 'required' })), + description: Yup.string().trim() + }); + + const formik = useFormik({ + enableReinitialize: true, + initialValues: {}, + validationSchema: ValidationSchema, + onSubmit: values => { + submitItemCategory({ values }) + .then(response => { + AppToaster.show({ + message: 'the_category_has_been_submit' + }); + }) + .catch(error => { + alert(error.message); + }); + } + }); + + const fetchHook = useAsync(async () => { + await Promise.all([submitItemCategory]); + }); + + const handleClose = () => { + closeDialog(name); + }; + + const onDialogOpening = () => { + fetchHook.execute(); + openDialog(name); + }; + const onDialogClosed = () => { + // formik.resetForm(); + closeDialog(name); + }; + + return ( + + + + + + + + + + + + + Close + + {payload.action === 'new' ? 'New' : 'Submit'} + + + + + + ); +} + +export default compose( + ItemFormDialogConnect, + DialogConnect, + DialogReduxConnect +)(ItemFromDialog); diff --git a/client/src/containers/Dashboard/Items/ItemCategoryList.js b/client/src/containers/Dashboard/Items/ItemCategoryList.js new file mode 100644 index 000000000..0f57a6910 --- /dev/null +++ b/client/src/containers/Dashboard/Items/ItemCategoryList.js @@ -0,0 +1,24 @@ +import React, { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import DashboardConnect from 'connectors/Dashboard.connector'; +import DashboardInsider from 'components/Dashboard/DashboardInsider'; +import CategoryList from 'components/Items/categoryList'; +import ItemFormDialog from 'connectors/ItemFormDialog.connect'; +import { compose } from 'utils'; + +const ItemCategoryList = ({ changePageTitle }) => { + const { id } = useParams(); + + useEffect(() => { + id + ? changePageTitle('Edit Category Details') + : changePageTitle('Category List'); + }, []); + return ( + + + + ); +}; + +export default compose(DashboardConnect, ItemFormDialog)(ItemCategoryList); diff --git a/client/src/routes/dashboard.js b/client/src/routes/dashboard.js index e319ea631..916821eca 100644 --- a/client/src/routes/dashboard.js +++ b/client/src/routes/dashboard.js @@ -71,13 +71,19 @@ export default [ path: `${BASE_URL}/items/list`, component: LazyLoader({ loader: () => import('containers/Dashboard/Items/ItemsList') - }), + }) }, { path: `${BASE_URL}/items/new`, component: LazyLoader({ loader: () => import('containers/Dashboard/Items/ItemForm') - }), + }) + }, + { + path: `${BASE_URL}/items/category`, + component: LazyLoader({ + loader: () => import('containers/Dashboard/Items/ItemCategoryList') + }) }, // Financial Reports. diff --git a/client/src/store/itemCategories/itemsCategory.actions.js b/client/src/store/itemCategories/itemsCategory.actions.js new file mode 100644 index 000000000..8611b58dd --- /dev/null +++ b/client/src/store/itemCategories/itemsCategory.actions.js @@ -0,0 +1,47 @@ +import ApiService from 'services/ApiService'; +import t from 'store/types'; + +export const submitCategory = ({ form }) => { + return dispatch => + new Promise((resolve, reject) => { + ApiService.post('item_categories', form) + .then(response => { + dispatch({ type: t.ITEMS_CATEGORY_LIST_SET }); + resolve(response); + }) + .catch(error => { + const { response } = error; + const { data } = response; + const { errors } = data; + + dispatch({ type: t.ITEMS_CATEGORY_LIST_SET }); + if (errors) { + dispatch({ type: t.ITEMS_CATEGORY_LIST_SET, errors }); + } + reject(error); + }); + }); +}; + +export const submitItemCategory = ({ form }) => { + return dispatch => { + return ApiService.post('item_categories', { ...form }); + }; +}; + +export const fetchCategory = () => { + return (dispatch, getState) => + new Promise((resolve, reject) => { + ApiService.get('item_categories') + .then(response => { + dispatch({ + type: t.ITEMS_CATEGORY_DATA_TABLE, + data: response.data + }); + resolve(response); + }) + .catch(error => { + reject(error); + }); + }); +}; diff --git a/client/src/store/itemCategories/itemsCategory.type.js b/client/src/store/itemCategories/itemsCategory.type.js new file mode 100644 index 000000000..d861caee0 --- /dev/null +++ b/client/src/store/itemCategories/itemsCategory.type.js @@ -0,0 +1,6 @@ +export default { + ITEMS_CATEGORY_LIST_SET: 'ITEMS_CATEGORY_LIST_SET', + ITEMS_CATEGORY_DATA_TABLE: 'ITEMS_CATEGORY_DATA_TABLE', + +}; + diff --git a/client/src/store/itemCategories/itemsCateory.reducer.js b/client/src/store/itemCategories/itemsCateory.reducer.js new file mode 100644 index 000000000..03d8da012 --- /dev/null +++ b/client/src/store/itemCategories/itemsCateory.reducer.js @@ -0,0 +1,27 @@ +import t from 'store/types'; +import { createReducer } from '@reduxjs/toolkit'; + +const initialState = { + categories: {}, + categoriesById: {} +}; + +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.CATEGORY_SET]: (state, action) => { + state.categoriesById[action.category.id] = action.category; + } +}); +export const getCategoryId = (state, id) => { + return state.categories.categoriesById[id]; +}; diff --git a/client/src/store/reducers.js b/client/src/store/reducers.js index abbd862fa..25d8ce0ba 100644 --- a/client/src/store/reducers.js +++ b/client/src/store/reducers.js @@ -11,6 +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/itemsCateory.reducer'; export default combineReducers({ authentication, @@ -24,4 +25,5 @@ export default combineReducers({ resources, financialStatements, items, -}); \ No newline at end of file + itemCategories +}); diff --git a/client/src/store/types.js b/client/src/store/types.js index d3db2d6bc..16604a866 100644 --- a/client/src/store/types.js +++ b/client/src/store/types.js @@ -10,7 +10,7 @@ import preferences from './preferences/preferences.types'; import resources from './resources/resource.types'; import users from './users/users.types'; import financialStatements from './financialStatement/financialStatements.types'; - +import itemCategories from './itemCategories/itemsCategory.type'; export default { ...authentication, ...accounts, @@ -24,4 +24,5 @@ export default { ...resources, ...users, ...financialStatements, -} \ No newline at end of file + ...itemCategories +};