mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
Merge branch 'feature/itemCategore'
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import AccountFormDialog from 'containers/Dashboard/Dialogs/AccountFormDialog';
|
import AccountFormDialog from 'containers/Dashboard/Dialogs/AccountFormDialog';
|
||||||
import UserFormDialog from 'containers/Dashboard/Dialogs/UserFormDialog';
|
import UserFormDialog from 'containers/Dashboard/Dialogs/UserFormDialog';
|
||||||
|
import ItemFromDialog from 'containers/Dashboard/Dialogs/ItemFromDialog';
|
||||||
|
|
||||||
export default function DialogsContainer() {
|
export default function DialogsContainer() {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<AccountFormDialog />
|
<AccountFormDialog />
|
||||||
{/* <UserFormDialog /> */}
|
<UserFormDialog />
|
||||||
|
<ItemFromDialog />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
60
client/src/components/Items/categoryList.js
Normal file
60
client/src/components/Items/categoryList.js
Normal file
@@ -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 (
|
||||||
|
<LoadingIndicator>
|
||||||
|
<GridComponent
|
||||||
|
allowSorting={true}
|
||||||
|
dataSource={columns}
|
||||||
|
enableVirtualization={true}
|
||||||
|
>
|
||||||
|
<ColumnsDirective>
|
||||||
|
<ColumnDirective type='checkbox'></ColumnDirective>
|
||||||
|
{/* {columns.map(column => {
|
||||||
|
return (
|
||||||
|
<ColumnDirective
|
||||||
|
field={column.field}
|
||||||
|
headerText={column.headerText}
|
||||||
|
allowSorting={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})} */}
|
||||||
|
</ColumnsDirective>
|
||||||
|
</GridComponent>
|
||||||
|
</LoadingIndicator>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default compose(DashboardConnect, ItemFormDialogConnect)(categoryList);
|
||||||
@@ -19,16 +19,20 @@ export default [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: 'Items List',
|
text: 'Items List',
|
||||||
href: '/dashboard/items/list',
|
href: '/dashboard/items/list'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'New Item',
|
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',
|
icon: 'balance-scale',
|
||||||
@@ -37,29 +41,25 @@ export default [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: 'Accounts Chart',
|
text: 'Accounts Chart',
|
||||||
href: '/dashboard/accounts',
|
href: '/dashboard/accounts'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Make Journal',
|
text: 'Make Journal',
|
||||||
href: '/dashboard/accounting/make-journal-entry'
|
href: '/dashboard/accounting/make-journal-entry'
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'university',
|
icon: 'university',
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
text: 'Banking',
|
text: 'Banking',
|
||||||
children: [
|
children: []
|
||||||
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'shopping-cart',
|
icon: 'shopping-cart',
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
text: 'Sales',
|
text: 'Sales',
|
||||||
children: [
|
children: []
|
||||||
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'balance-scale',
|
icon: 'balance-scale',
|
||||||
@@ -81,24 +81,24 @@ export default [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: 'Balance Sheet',
|
text: 'Balance Sheet',
|
||||||
href: '/dashboard/accounting/balance-sheet',
|
href: '/dashboard/accounting/balance-sheet'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Trial Balance Sheet',
|
text: 'Trial Balance Sheet',
|
||||||
href: '/dashboard/accounting/trial-balance-sheet',
|
href: '/dashboard/accounting/trial-balance-sheet'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Journal',
|
text: 'Journal',
|
||||||
href: '/dashboard/accounting/journal-sheet',
|
href: '/dashboard/accounting/journal-sheet'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'General Ledger',
|
text: 'General Ledger',
|
||||||
href: '/dashboard/accounting/general-ledger',
|
href: '/dashboard/accounting/general-ledger'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Profit Loss Sheet',
|
text: 'Profit Loss Sheet',
|
||||||
href: '/dashboard/accounting/profit-loss-sheet',
|
href: '/dashboard/accounting/profit-loss-sheet'
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -108,12 +108,12 @@ export default [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: 'Expenses List',
|
text: 'Expenses List',
|
||||||
href: '/dashboard/expenses',
|
href: '/dashboard/expenses'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'New Expenses',
|
text: 'New Expenses',
|
||||||
href: '/dashboard/expenses/new',
|
href: '/dashboard/expenses/new'
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
24
client/src/connectors/ItemFormDialog.connect.js
Normal file
24
client/src/connectors/ItemFormDialog.connect.js
Normal file
@@ -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);
|
||||||
130
client/src/containers/Dashboard/Dialogs/ItemFromDialog.js
Normal file
130
client/src/containers/Dashboard/Dialogs/ItemFromDialog.js
Normal file
@@ -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 (
|
||||||
|
<Dialog
|
||||||
|
name={name}
|
||||||
|
title={payload.action === 'new' ? 'New' : ' New Category'}
|
||||||
|
className={{
|
||||||
|
'dialog--loading': state.isLoading,
|
||||||
|
'dialog--item-form': true
|
||||||
|
}}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClosed={onDialogClosed}
|
||||||
|
onOpening={onDialogOpening}
|
||||||
|
isLoading={fetchHook.pending}
|
||||||
|
>
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<div className={Classes.DIALOG_BODY}>
|
||||||
|
<FormGroup
|
||||||
|
label={'Category Name'}
|
||||||
|
className={'form-group--category-name'}
|
||||||
|
intent={formik.errors.name && Intent.DANGER}
|
||||||
|
helperText={formik.errors.name && formik.errors.name}
|
||||||
|
inline={true}
|
||||||
|
>
|
||||||
|
<InputGroup
|
||||||
|
medium={formik.values.toString()}
|
||||||
|
intent={formik.errors.name && Intent.DANGER}
|
||||||
|
{...formik.getFieldProps('name')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={'Description'}
|
||||||
|
className={'form-group--description'}
|
||||||
|
intent={formik.errors.description && Intent.DANGER}
|
||||||
|
helperText={formik.errors.description && formik.errors.credential}
|
||||||
|
inline={true}
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
growVertically={true}
|
||||||
|
large={true}
|
||||||
|
{...formik.getFieldProps('description')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</div>
|
||||||
|
<div className={Classes.DIALOG_FOOTER}>
|
||||||
|
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||||
|
<Button onClick={handleClose}>Close</Button>
|
||||||
|
<Button intent={Intent.PRIMARY} type='submit'>
|
||||||
|
{payload.action === 'new' ? 'New' : 'Submit'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
ItemFormDialogConnect,
|
||||||
|
DialogConnect,
|
||||||
|
DialogReduxConnect
|
||||||
|
)(ItemFromDialog);
|
||||||
24
client/src/containers/Dashboard/Items/ItemCategoryList.js
Normal file
24
client/src/containers/Dashboard/Items/ItemCategoryList.js
Normal file
@@ -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 (
|
||||||
|
<DashboardInsider isLoading={null} name={'item-category-list'}>
|
||||||
|
<CategoryList />
|
||||||
|
</DashboardInsider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default compose(DashboardConnect, ItemFormDialog)(ItemCategoryList);
|
||||||
@@ -71,13 +71,19 @@ export default [
|
|||||||
path: `${BASE_URL}/items/list`,
|
path: `${BASE_URL}/items/list`,
|
||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () => import('containers/Dashboard/Items/ItemsList')
|
loader: () => import('containers/Dashboard/Items/ItemsList')
|
||||||
}),
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/items/new`,
|
path: `${BASE_URL}/items/new`,
|
||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () => import('containers/Dashboard/Items/ItemForm')
|
loader: () => import('containers/Dashboard/Items/ItemForm')
|
||||||
}),
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: `${BASE_URL}/items/category`,
|
||||||
|
component: LazyLoader({
|
||||||
|
loader: () => import('containers/Dashboard/Items/ItemCategoryList')
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// Financial Reports.
|
// Financial Reports.
|
||||||
|
|||||||
47
client/src/store/itemCategories/itemsCategory.actions.js
Normal file
47
client/src/store/itemCategories/itemsCategory.actions.js
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
6
client/src/store/itemCategories/itemsCategory.type.js
Normal file
6
client/src/store/itemCategories/itemsCategory.type.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
ITEMS_CATEGORY_LIST_SET: 'ITEMS_CATEGORY_LIST_SET',
|
||||||
|
ITEMS_CATEGORY_DATA_TABLE: 'ITEMS_CATEGORY_DATA_TABLE',
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
27
client/src/store/itemCategories/itemsCateory.reducer.js
Normal file
27
client/src/store/itemCategories/itemsCateory.reducer.js
Normal file
@@ -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];
|
||||||
|
};
|
||||||
@@ -11,6 +11,7 @@ import expenses from './expenses/expenses.reducer';
|
|||||||
import currencies from './currencies/currencies.reducer';
|
import currencies from './currencies/currencies.reducer';
|
||||||
import resources from './resources/resources.reducer';
|
import resources from './resources/resources.reducer';
|
||||||
import financialStatements from './financialStatement/financialStatements.reducer';
|
import financialStatements from './financialStatement/financialStatements.reducer';
|
||||||
|
import itemCategories from './itemCategories/itemsCateory.reducer';
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
authentication,
|
authentication,
|
||||||
@@ -24,4 +25,5 @@ export default combineReducers({
|
|||||||
resources,
|
resources,
|
||||||
financialStatements,
|
financialStatements,
|
||||||
items,
|
items,
|
||||||
});
|
itemCategories
|
||||||
|
});
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import preferences from './preferences/preferences.types';
|
|||||||
import resources from './resources/resource.types';
|
import resources from './resources/resource.types';
|
||||||
import users from './users/users.types';
|
import users from './users/users.types';
|
||||||
import financialStatements from './financialStatement/financialStatements.types';
|
import financialStatements from './financialStatement/financialStatements.types';
|
||||||
|
import itemCategories from './itemCategories/itemsCategory.type';
|
||||||
export default {
|
export default {
|
||||||
...authentication,
|
...authentication,
|
||||||
...accounts,
|
...accounts,
|
||||||
@@ -24,4 +24,5 @@ export default {
|
|||||||
...resources,
|
...resources,
|
||||||
...users,
|
...users,
|
||||||
...financialStatements,
|
...financialStatements,
|
||||||
}
|
...itemCategories
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user