mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 22:00:31 +00:00
Config With Seacrh
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {connect} from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {useHistory} from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
import {
|
import {
|
||||||
Navbar,
|
Navbar,
|
||||||
NavbarGroup,
|
NavbarGroup,
|
||||||
@@ -14,59 +14,79 @@ import {
|
|||||||
import DashboardBreadcrumbs from 'components/Dashboard/DashboardBreadcrumbs';
|
import DashboardBreadcrumbs from 'components/Dashboard/DashboardBreadcrumbs';
|
||||||
import DashboardTopbarUser from 'components/Dashboard/TopbarUser';
|
import DashboardTopbarUser from 'components/Dashboard/TopbarUser';
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
|
import Search from 'containers/Dashboard/GeneralSearch/Search';
|
||||||
|
|
||||||
function DashboardTopbar({
|
function DashboardTopbar({ pageTitle, pageSubtitle, editViewId }) {
|
||||||
pageTitle,
|
|
||||||
pageSubtitle,
|
|
||||||
editViewId,
|
|
||||||
}) {
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const handlerClickEditView = () => {
|
const handlerClickEditView = () => {
|
||||||
history.push(`/dashboard/custom_views/${editViewId}/edit`)
|
history.push(`/dashboard/custom_views/${editViewId}/edit`);
|
||||||
}
|
};
|
||||||
|
|
||||||
const maybleRenderPageSubtitle = pageSubtitle && (<h3>{ pageSubtitle }</h3>);
|
const maybleRenderPageSubtitle = pageSubtitle && <h3>{pageSubtitle}</h3>;
|
||||||
const maybeRenderEditViewBtn = (pageSubtitle && editViewId) && (
|
const maybeRenderEditViewBtn = pageSubtitle && editViewId && (
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL + ' button--view-edit'}
|
className={Classes.MINIMAL + ' button--view-edit'}
|
||||||
icon={<Icon icon="pen" iconSize={13} />}
|
icon={<Icon icon='pen' iconSize={13} />}
|
||||||
onClick={handlerClickEditView} />
|
onClick={handlerClickEditView}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div class="dashboard__topbar">
|
<div class='dashboard__topbar'>
|
||||||
<div class="dashboard__topbar-left">
|
<div class='dashboard__topbar-left'>
|
||||||
<div class="dashboard__topbar-sidebar-toggle">
|
<div class='dashboard__topbar-sidebar-toggle'>
|
||||||
<Button>
|
<Button>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" role="img" focusable="false">
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
width='20'
|
||||||
|
height='20'
|
||||||
|
viewBox='0 0 20 20'
|
||||||
|
role='img'
|
||||||
|
focusable='false'
|
||||||
|
>
|
||||||
<title>Menu</title>
|
<title>Menu</title>
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="5" stroke-width="2" d="M4 7h15M4 12h15M4 17h15"></path>
|
<path
|
||||||
|
stroke='currentColor'
|
||||||
|
stroke-linecap='round'
|
||||||
|
stroke-miterlimit='5'
|
||||||
|
stroke-width='2'
|
||||||
|
d='M4 7h15M4 12h15M4 17h15'
|
||||||
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dashboard__title">
|
<div class='dashboard__title'>
|
||||||
<h1>{ pageTitle }</h1>
|
<h1>{pageTitle}</h1>
|
||||||
{maybleRenderPageSubtitle}
|
{maybleRenderPageSubtitle}
|
||||||
{maybeRenderEditViewBtn}
|
{maybeRenderEditViewBtn}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dashboard__breadcrumbs">
|
<div class='dashboard__breadcrumbs'>
|
||||||
<DashboardBreadcrumbs />
|
<DashboardBreadcrumbs />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dashboard__topbar-right">
|
<div class='dashboard__topbar-right'>
|
||||||
<Navbar class="dashboard__topbar-navbar">
|
<Navbar class='dashboard__topbar-navbar'>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
<Button className={Classes.MINIMAL} icon="home" text="Search" />
|
{/* <Button className={Classes.MINIMAL} icon="home" text="Search" /> */}
|
||||||
<Button className={Classes.MINIMAL} icon="document" text="Filters" />
|
<Search className />
|
||||||
<Button className={Classes.MINIMAL} icon="document" text="Add order" />
|
<Button
|
||||||
<Button className={Classes.MINIMAL} icon="document" text="More" />
|
className={Classes.MINIMAL}
|
||||||
|
icon='document'
|
||||||
|
text='Filters'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className={Classes.MINIMAL}
|
||||||
|
icon='document'
|
||||||
|
text='Add order'
|
||||||
|
/>
|
||||||
|
<Button className={Classes.MINIMAL} icon='document' text='More' />
|
||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
|
|
||||||
<div class="dashboard__topbar-user">
|
<div class='dashboard__topbar-user'>
|
||||||
<DashboardTopbarUser />
|
<DashboardTopbarUser />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,7 +97,7 @@ function DashboardTopbar({
|
|||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
pageTitle: state.dashboard.pageTitle,
|
pageTitle: state.dashboard.pageTitle,
|
||||||
pageSubtitle: state.dashboard.pageSubtitle,
|
pageSubtitle: state.dashboard.pageSubtitle,
|
||||||
editViewId: state.dashboard.topbarEditViewId,
|
editViewId: state.dashboard.topbarEditViewId,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(DashboardTopbar);
|
export default connect(mapStateToProps)(DashboardTopbar);
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
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);
|
|
||||||
@@ -18,7 +18,6 @@ import { useUpdateEffect } from 'hooks';
|
|||||||
|
|
||||||
function ManualJournalsViewTabs({
|
function ManualJournalsViewTabs({
|
||||||
views,
|
views,
|
||||||
manualJournals,
|
|
||||||
setTopbarEditView,
|
setTopbarEditView,
|
||||||
customViewChanged,
|
customViewChanged,
|
||||||
addManualJournalsTableQueries,
|
addManualJournalsTableQueries,
|
||||||
@@ -51,8 +50,6 @@ function ManualJournalsViewTabs({
|
|||||||
}, [customViewId]);
|
}, [customViewId]);
|
||||||
|
|
||||||
const tabs = views.map((view) => {
|
const tabs = views.map((view) => {
|
||||||
//FIXME: dashboard/accounting/make-journal-entry
|
|
||||||
|
|
||||||
const baseUrl = '/dashboard/accounting/manual-journals';
|
const baseUrl = '/dashboard/accounting/manual-journals';
|
||||||
const link = (
|
const link = (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
13
client/src/connectors/Search.connect.js
Normal file
13
client/src/connectors/Search.connect.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import t from 'store/types';
|
||||||
|
import { generalSearch } from 'store/search/search.actions';
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, props) => ({
|
||||||
|
resultSearch: state.GeneralSearch,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch) => ({
|
||||||
|
generalSearch: (result) => dispatch(generalSearch(result)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps);
|
||||||
74
client/src/containers/Dashboard/GeneralSearch/Search.js
Normal file
74
client/src/containers/Dashboard/GeneralSearch/Search.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Omnibar } from '@blueprintjs/select';
|
||||||
|
import { MenuItem, Button, Classes } from '@blueprintjs/core';
|
||||||
|
import { useAsync } from 'react-use';
|
||||||
|
import * as Yup from 'yup';
|
||||||
|
import { useFormik } from 'formik';
|
||||||
|
import Icon from 'components/Icon';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
import SearchConnect from 'connectors/Search.connect';
|
||||||
|
|
||||||
|
function Search({}) {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{ title: 'The Shawshank Redemption', year: 1994 },
|
||||||
|
{ title: 'The Godfather', year: 1972 },
|
||||||
|
{ title: 'The Godfather: Part II', year: 1974 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
name: Yup.string().required(),
|
||||||
|
});
|
||||||
|
const formik = useFormik({
|
||||||
|
enableReinitialize: true,
|
||||||
|
validationSchema: validationSchema,
|
||||||
|
initialValues: {},
|
||||||
|
});
|
||||||
|
const renderSearch = (search, { handleClick, modifiers }) => (
|
||||||
|
<MenuItem
|
||||||
|
active={modifiers.active}
|
||||||
|
key={search.id}
|
||||||
|
text={search.name}
|
||||||
|
label={search.name}
|
||||||
|
onClick={handleClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const filterSearch = (query, search, _index, exactMatch) => {
|
||||||
|
// const normalizedTitle = search.toLowerCase();
|
||||||
|
// const normalizedQuery = query.toLowerCase();
|
||||||
|
// if (exactMatch) {
|
||||||
|
// return normalizedTitle === normalizedQuery;
|
||||||
|
// } else {
|
||||||
|
// return `${search} ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
||||||
|
// }
|
||||||
|
return search;
|
||||||
|
};
|
||||||
|
const handleClick = () => setIsOpen(true);
|
||||||
|
const handleClose = () => setIsOpen(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
className={Classes.MINIMAL}
|
||||||
|
icon='home'
|
||||||
|
text='Search'
|
||||||
|
onClick={handleClick}
|
||||||
|
/>
|
||||||
|
<Omnibar
|
||||||
|
isOpen={isOpen}
|
||||||
|
noResults={<MenuItem disabled={true} text='No results.' />}
|
||||||
|
onClose={handleClose}
|
||||||
|
resetOnSelect={true}
|
||||||
|
itemRenderer={renderSearch}
|
||||||
|
items={items}
|
||||||
|
// onItemSelect={}
|
||||||
|
itemListPredicate={filterSearch}
|
||||||
|
// style={{ position: 'absolute', canter: '50%' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(SearchConnect)(Search);
|
||||||
@@ -2,7 +2,7 @@ import ApiService from 'services/ApiService';
|
|||||||
import t from 'store/types';
|
import t from 'store/types';
|
||||||
|
|
||||||
export const submitItemCategory = ({ form }) => {
|
export const submitItemCategory = ({ form }) => {
|
||||||
return dispatch => {
|
return (dispatch) => {
|
||||||
return ApiService.post('item_categories', { ...form });
|
return ApiService.post('item_categories', { ...form });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -11,53 +11,53 @@ export const fetchItemCategories = () => {
|
|||||||
return (dispatch, getState) =>
|
return (dispatch, getState) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
ApiService.get('item_categories')
|
ApiService.get('item_categories')
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.ITEMS_CATEGORY_LIST_SET,
|
type: t.ITEMS_CATEGORY_LIST_SET,
|
||||||
categories: response.data.categories
|
categories: response.data.categories,
|
||||||
});
|
});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const editItemCategory = (id, form) => {
|
export const editItemCategory = (id, form) => {
|
||||||
return dispatch =>
|
return (dispatch) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
ApiService.post(`item_categories/${id}`, form)
|
ApiService.post(`item_categories/${id}`, form)
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
dispatch({ type: t.CLEAR_CATEGORY_FORM_ERRORS });
|
dispatch({ type: t.CLEAR_CATEGORY_FORM_ERRORS });
|
||||||
resolve(response);
|
resolve(response);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
const { response } = error;
|
const { response } = error;
|
||||||
const { data } = response;
|
const { data } = response;
|
||||||
const { errors } = data;
|
const { errors } = data;
|
||||||
|
|
||||||
dispatch({ type: t.CLEAR_CATEGORY_FORM_ERRORS });
|
dispatch({ type: t.CLEAR_CATEGORY_FORM_ERRORS });
|
||||||
if (errors) {
|
if (errors) {
|
||||||
dispatch({ type: t.CATEGORY_FORM_ERRORS, errors });
|
dispatch({ type: t.CLEAR_CATEGORY_FORM_ERRORS, errors });
|
||||||
}
|
}
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteItemCategory = id => {
|
export const deleteItemCategory = (id) => {
|
||||||
return dispatch =>
|
return (dispatch) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
ApiService.delete(`item_categories/${id}`)
|
ApiService.delete(`item_categories/${id}`)
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.CATEGORY_DELETE,
|
type: t.CATEGORY_DELETE,
|
||||||
id
|
id,
|
||||||
});
|
});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import financialStatements from './financialStatement/financialStatements.reduce
|
|||||||
import itemCategories from './itemCategories/itemsCategory.reducer';
|
import itemCategories from './itemCategories/itemsCategory.reducer';
|
||||||
import settings from './settings/settings.reducer';
|
import settings from './settings/settings.reducer';
|
||||||
import manualJournals from './manualJournals/manualJournals.reducers';
|
import manualJournals from './manualJournals/manualJournals.reducers';
|
||||||
|
import search from './search/search.reducer';
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
authentication,
|
authentication,
|
||||||
@@ -30,4 +31,5 @@ export default combineReducers({
|
|||||||
items,
|
items,
|
||||||
itemCategories,
|
itemCategories,
|
||||||
settings,
|
settings,
|
||||||
|
search,
|
||||||
});
|
});
|
||||||
|
|||||||
8
client/src/store/search/search.actions.js
Normal file
8
client/src/store/search/search.actions.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import t from 'store/types';
|
||||||
|
|
||||||
|
export function generalSearch(name, result) {
|
||||||
|
return {
|
||||||
|
type: t.SEARCH_SUCCESS,
|
||||||
|
result,
|
||||||
|
};
|
||||||
|
}
|
||||||
33
client/src/store/search/search.reducer.js
Normal file
33
client/src/store/search/search.reducer.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import t from 'store/types';
|
||||||
|
import { createReducer } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
searches: {},
|
||||||
|
searchTitle: 'Title',
|
||||||
|
isOpen: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createReducer(initialState, {
|
||||||
|
[t.SEARCH_SUCCESS]: (state, action) => {
|
||||||
|
const _result = {};
|
||||||
|
|
||||||
|
action.searches.forEach((search) => {
|
||||||
|
_result[search.id] = search;
|
||||||
|
});
|
||||||
|
|
||||||
|
state.searches = {
|
||||||
|
...state.searches,
|
||||||
|
..._result,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// return state = action.result;
|
||||||
|
// if (typeof state === 'undefined') {
|
||||||
|
// return initialState;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// state.search[action.name] = {
|
||||||
|
// isOpen: true,
|
||||||
|
// payload: action.payload || {},
|
||||||
|
// };
|
||||||
5
client/src/store/search/search.type.js
Normal file
5
client/src/store/search/search.type.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export default {
|
||||||
|
SEARCH_SUCCESS: 'SEARCH_SUCCESS',
|
||||||
|
SEARCH_FAILURE: 'SEARCH_FAILURE',
|
||||||
|
SEARCH_REQUEST: 'SEARCH_REQUEST',
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import authentication from './authentication/authentication.types';
|
import authentication from './authentication/authentication.types';
|
||||||
import accounts from './accounts/accounts.types';
|
import accounts from './accounts/accounts.types';
|
||||||
import accounting from './manualJournals/manualJournals.types'
|
import accounting from './manualJournals/manualJournals.types';
|
||||||
import currencies from './currencies/currencies.types';
|
import currencies from './currencies/currencies.types';
|
||||||
import customFields from './customFields/customFields.types';
|
import customFields from './customFields/customFields.types';
|
||||||
import customViews from './customViews/customViews.types';
|
import customViews from './customViews/customViews.types';
|
||||||
@@ -13,7 +13,7 @@ import users from './users/users.types';
|
|||||||
import financialStatements from './financialStatement/financialStatements.types';
|
import financialStatements from './financialStatement/financialStatements.types';
|
||||||
import itemCategories from './itemCategories/itemsCategory.type';
|
import itemCategories from './itemCategories/itemsCategory.type';
|
||||||
import settings from './settings/settings.type';
|
import settings from './settings/settings.type';
|
||||||
|
import search from './search/search.type';
|
||||||
export default {
|
export default {
|
||||||
...authentication,
|
...authentication,
|
||||||
...accounts,
|
...accounts,
|
||||||
@@ -30,4 +30,5 @@ export default {
|
|||||||
...itemCategories,
|
...itemCategories,
|
||||||
...settings,
|
...settings,
|
||||||
...accounting,
|
...accounting,
|
||||||
|
...search,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,30 +15,40 @@ export default {
|
|||||||
|
|
||||||
router.use(JWTAuth);
|
router.use(JWTAuth);
|
||||||
|
|
||||||
router.post('/:id',
|
router.post(
|
||||||
|
'/:id',
|
||||||
// permit('create', 'edit'),
|
// permit('create', 'edit'),
|
||||||
this.editCategory.validation,
|
this.editCategory.validation,
|
||||||
asyncMiddleware(this.editCategory.handler));
|
asyncMiddleware(this.editCategory.handler)
|
||||||
|
);
|
||||||
|
|
||||||
router.post('/',
|
router.post(
|
||||||
|
'/',
|
||||||
// permit('create'),
|
// permit('create'),
|
||||||
this.newCategory.validation,
|
this.newCategory.validation,
|
||||||
asyncMiddleware(this.newCategory.handler));
|
asyncMiddleware(this.newCategory.handler)
|
||||||
|
);
|
||||||
|
|
||||||
router.delete('/:id',
|
router.delete(
|
||||||
|
'/:id',
|
||||||
// permit('create', 'edit', 'delete'),
|
// permit('create', 'edit', 'delete'),
|
||||||
this.deleteItem.validation,
|
this.deleteItem.validation,
|
||||||
asyncMiddleware(this.deleteItem.handler));
|
asyncMiddleware(this.deleteItem.handler)
|
||||||
|
);
|
||||||
|
|
||||||
router.get('/:id',
|
router.get(
|
||||||
|
'/:id',
|
||||||
// permit('view'),
|
// permit('view'),
|
||||||
this.getCategory.validation,
|
this.getCategory.validation,
|
||||||
asyncMiddleware(this.getCategory.handler));
|
asyncMiddleware(this.getCategory.handler)
|
||||||
|
);
|
||||||
|
|
||||||
router.get('/',
|
router.get(
|
||||||
|
'/',
|
||||||
// permit('view'),
|
// permit('view'),
|
||||||
this.getList.validation,
|
this.getList.validation,
|
||||||
asyncMiddleware(this.getList.handler));
|
asyncMiddleware(this.getList.handler)
|
||||||
|
);
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
},
|
},
|
||||||
@@ -48,16 +58,26 @@ export default {
|
|||||||
*/
|
*/
|
||||||
newCategory: {
|
newCategory: {
|
||||||
validation: [
|
validation: [
|
||||||
check('name').exists().trim().escape(),
|
check('name')
|
||||||
check('parent_category_id').optional().isNumeric().toInt(),
|
.exists()
|
||||||
check('description').optional().trim().escape(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
|
check('parent_category_id')
|
||||||
|
.optional({ nullable: true, checkFalsy: true })
|
||||||
|
.isNumeric()
|
||||||
|
.toInt(),
|
||||||
|
check('description')
|
||||||
|
.optional()
|
||||||
|
.trim()
|
||||||
|
.escape()
|
||||||
],
|
],
|
||||||
async handler(req, res) {
|
async handler(req, res) {
|
||||||
const validationErrors = validationResult(req);
|
const validationErrors = validationResult(req);
|
||||||
|
|
||||||
if (!validationErrors.isEmpty()) {
|
if (!validationErrors.isEmpty()) {
|
||||||
return res.boom.badData(null, {
|
return res.boom.badData(null, {
|
||||||
code: 'validation_error', ...validationErrors,
|
code: 'validation_error',
|
||||||
|
...validationErrors
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,20 +86,21 @@ export default {
|
|||||||
|
|
||||||
if (form.parent_category_id) {
|
if (form.parent_category_id) {
|
||||||
const foundParentCategory = await ItemCategory.query()
|
const foundParentCategory = await ItemCategory.query()
|
||||||
.where('id', form.parent_category_id).first();
|
.where('id', form.parent_category_id)
|
||||||
|
.first();
|
||||||
|
|
||||||
if (!foundParentCategory) {
|
if (!foundParentCategory) {
|
||||||
return res.boom.notFound('The parent category ID is not found.', {
|
return res.boom.notFound('The parent category ID is not found.', {
|
||||||
errors: [{ type: 'PARENT_CATEGORY_NOT_FOUND', code: 100 }],
|
errors: [{ type: 'PARENT_CATEGORY_NOT_FOUND', code: 100 }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const category = await ItemCategory.query().insert({
|
const category = await ItemCategory.query().insert({
|
||||||
...form,
|
...form,
|
||||||
user_id: user.id,
|
user_id: user.id
|
||||||
});
|
});
|
||||||
return res.status(200).send({ category });
|
return res.status(200).send({ category });
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,9 +109,18 @@ export default {
|
|||||||
editCategory: {
|
editCategory: {
|
||||||
validation: [
|
validation: [
|
||||||
param('id').toInt(),
|
param('id').toInt(),
|
||||||
check('name').exists().trim().escape(),
|
check('name')
|
||||||
check('parent_category_id').optional().isNumeric().toInt(),
|
.exists()
|
||||||
check('description').optional().trim().escape(),
|
.trim()
|
||||||
|
.escape(),
|
||||||
|
check('parent_category_id')
|
||||||
|
.optional({ nullable: true, checkFalsy: true })
|
||||||
|
.isNumeric()
|
||||||
|
.toInt(),
|
||||||
|
check('description')
|
||||||
|
.optional()
|
||||||
|
.trim()
|
||||||
|
.escape()
|
||||||
],
|
],
|
||||||
async handler(req, res) {
|
async handler(req, res) {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
@@ -98,33 +128,41 @@ export default {
|
|||||||
|
|
||||||
if (!validationErrors.isEmpty()) {
|
if (!validationErrors.isEmpty()) {
|
||||||
return res.boom.badData(null, {
|
return res.boom.badData(null, {
|
||||||
code: 'validation_error', ...validationErrors,
|
code: 'validation_error',
|
||||||
|
...validationErrors
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const form = { ...req.body };
|
const form = { ...req.body };
|
||||||
const itemCategory = await ItemCategory.query().where('id', id).first()
|
const itemCategory = await ItemCategory.query()
|
||||||
|
.where('id', id)
|
||||||
|
.first();
|
||||||
|
|
||||||
if (!itemCategory) {
|
if (!itemCategory) {
|
||||||
return res.boom.notFound({
|
return res.boom.notFound({
|
||||||
errors: [{ type: 'ITEM_CATEGORY.NOT.FOUND', code: 100 }],
|
errors: [{ type: 'ITEM_CATEGORY.NOT.FOUND', code: 100 }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (form.parent_category_id
|
if (
|
||||||
&& form.parent_category_id !== itemCategory.parent_category_id) {
|
form.parent_category_id &&
|
||||||
|
form.parent_category_id !== itemCategory.parent_category_id
|
||||||
|
) {
|
||||||
const foundParentCategory = await ItemCategory.query()
|
const foundParentCategory = await ItemCategory.query()
|
||||||
.where('id', form.parent_category_id).first();
|
.where('id', form.parent_category_id)
|
||||||
|
.first();
|
||||||
|
|
||||||
if (!foundParentCategory) {
|
if (!foundParentCategory) {
|
||||||
return res.boom.notFound('The parent category ID is not found.', {
|
return res.boom.notFound('The parent category ID is not found.', {
|
||||||
errors: [{ type: 'PARENT_CATEGORY_NOT_FOUND', code: 100 }],
|
errors: [{ type: 'PARENT_CATEGORY_NOT_FOUND', code: 100 }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const updateItemCategory = await ItemCategory.query().where('id', id).update({ ...form });
|
const updateItemCategory = await ItemCategory.query()
|
||||||
|
.where('id', id)
|
||||||
|
.update({ ...form });
|
||||||
|
|
||||||
return res.status(200).send({ id: updateItemCategory });
|
return res.status(200).send({ id: updateItemCategory });
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,20 +170,26 @@ export default {
|
|||||||
*/
|
*/
|
||||||
deleteItem: {
|
deleteItem: {
|
||||||
validation: [
|
validation: [
|
||||||
param('id').exists().toInt(),
|
param('id')
|
||||||
|
.exists()
|
||||||
|
.toInt()
|
||||||
],
|
],
|
||||||
async handler(req, res) {
|
async handler(req, res) {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const itemCategory = await ItemCategory.query().where('id', id).first();
|
const itemCategory = await ItemCategory.query()
|
||||||
|
.where('id', id)
|
||||||
|
.first();
|
||||||
|
|
||||||
if (!itemCategory) {
|
if (!itemCategory) {
|
||||||
return res.boom.notFound();
|
return res.boom.notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
await ItemCategory.query().where('id', itemCategory.id).delete();
|
await ItemCategory.query()
|
||||||
|
.where('id', itemCategory.id)
|
||||||
|
.delete();
|
||||||
|
|
||||||
return res.status(200).send();
|
return res.status(200).send();
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -157,27 +201,25 @@ export default {
|
|||||||
const categories = await ItemCategory.query();
|
const categories = await ItemCategory.query();
|
||||||
|
|
||||||
return res.status(200).send({ categories });
|
return res.status(200).send({ categories });
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve details of the given category.
|
* Retrieve details of the given category.
|
||||||
*/
|
*/
|
||||||
getCategory: {
|
getCategory: {
|
||||||
validation: [
|
validation: [param('category_id').toInt()],
|
||||||
param('category_id').toInt(),
|
|
||||||
],
|
|
||||||
async handler(req, res) {
|
async handler(req, res) {
|
||||||
const { category_id: categoryId } = req.params;
|
const { category_id: categoryId } = req.params;
|
||||||
const item = await ItemCategory.where('id', categoryId).fetch();
|
const item = await ItemCategory.where('id', categoryId).fetch();
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return res.boom.notFound(null, {
|
return res.boom.notFound(null, {
|
||||||
errors: [{ type: 'CATEGORY_NOT_FOUND', code: 100 }],
|
errors: [{ type: 'CATEGORY_NOT_FOUND', code: 100 }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).send({ category: item.toJSON() });
|
return res.status(200).send({ category: item.toJSON() });
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user