From 940418c4e0fefbf1f28c4497a5542a856a3d63e4 Mon Sep 17 00:00:00 2001 From: elforjani3 Date: Sat, 11 Apr 2020 15:00:22 +0200 Subject: [PATCH] Config With Seacrh --- .../components/Dashboard/DashboardTopbar.js | 80 ++++++----- client/src/components/Items/categoryList.js | 60 --------- .../JournalEntry/ManualJournalsViewTabs.js | 3 - client/src/connectors/Search.connect.js | 13 ++ .../Dashboard/GeneralSearch/Search.js | 74 +++++++++++ .../itemCategories/itemsCategory.actions.js | 26 ++-- client/src/store/reducers.js | 2 + client/src/store/search/search.actions.js | 8 ++ client/src/store/search/search.reducer.js | 33 +++++ client/src/store/search/search.type.js | 5 + client/src/store/types.js | 5 +- server/src/http/controllers/ItemCategories.js | 124 ++++++++++++------ 12 files changed, 284 insertions(+), 149 deletions(-) delete mode 100644 client/src/components/Items/categoryList.js create mode 100644 client/src/connectors/Search.connect.js create mode 100644 client/src/containers/Dashboard/GeneralSearch/Search.js create mode 100644 client/src/store/search/search.actions.js create mode 100644 client/src/store/search/search.reducer.js create mode 100644 client/src/store/search/search.type.js diff --git a/client/src/components/Dashboard/DashboardTopbar.js b/client/src/components/Dashboard/DashboardTopbar.js index f889b0a35..7b551f7fa 100644 --- a/client/src/components/Dashboard/DashboardTopbar.js +++ b/client/src/components/Dashboard/DashboardTopbar.js @@ -1,6 +1,6 @@ import React from 'react'; -import {connect} from 'react-redux'; -import {useHistory} from 'react-router'; +import { connect } from 'react-redux'; +import { useHistory } from 'react-router'; import { Navbar, NavbarGroup, @@ -14,59 +14,79 @@ import { import DashboardBreadcrumbs from 'components/Dashboard/DashboardBreadcrumbs'; import DashboardTopbarUser from 'components/Dashboard/TopbarUser'; import Icon from 'components/Icon'; +import Search from 'containers/Dashboard/GeneralSearch/Search'; -function DashboardTopbar({ - pageTitle, - pageSubtitle, - editViewId, -}) { +function DashboardTopbar({ pageTitle, pageSubtitle, editViewId }) { const history = useHistory(); const handlerClickEditView = () => { - history.push(`/dashboard/custom_views/${editViewId}/edit`) - } + history.push(`/dashboard/custom_views/${editViewId}/edit`); + }; - const maybleRenderPageSubtitle = pageSubtitle && (

{ pageSubtitle }

); - const maybeRenderEditViewBtn = (pageSubtitle && editViewId) && ( + const maybleRenderPageSubtitle = pageSubtitle &&

{pageSubtitle}

; + const maybeRenderEditViewBtn = pageSubtitle && editViewId && ( -
-

{ pageTitle }

+
+

{pageTitle}

{maybleRenderPageSubtitle} {maybeRenderEditViewBtn}
-
+
-
- +
+ -
+ ); +} + +export default compose(SearchConnect)(Search); diff --git a/client/src/store/itemCategories/itemsCategory.actions.js b/client/src/store/itemCategories/itemsCategory.actions.js index 2469d4459..5a4b3ae20 100644 --- a/client/src/store/itemCategories/itemsCategory.actions.js +++ b/client/src/store/itemCategories/itemsCategory.actions.js @@ -2,7 +2,7 @@ import ApiService from 'services/ApiService'; import t from 'store/types'; export const submitItemCategory = ({ form }) => { - return dispatch => { + return (dispatch) => { return ApiService.post('item_categories', { ...form }); }; }; @@ -11,53 +11,53 @@ export const fetchItemCategories = () => { return (dispatch, getState) => new Promise((resolve, reject) => { ApiService.get('item_categories') - .then(response => { + .then((response) => { dispatch({ type: t.ITEMS_CATEGORY_LIST_SET, - categories: response.data.categories + categories: response.data.categories, }); resolve(response); }) - .catch(error => { + .catch((error) => { reject(error); }); }); }; export const editItemCategory = (id, form) => { - return dispatch => + return (dispatch) => new Promise((resolve, reject) => { ApiService.post(`item_categories/${id}`, form) - .then(response => { + .then((response) => { dispatch({ type: t.CLEAR_CATEGORY_FORM_ERRORS }); resolve(response); }) - .catch(error => { + .catch((error) => { const { response } = error; const { data } = response; const { errors } = data; dispatch({ type: t.CLEAR_CATEGORY_FORM_ERRORS }); if (errors) { - dispatch({ type: t.CATEGORY_FORM_ERRORS, errors }); + dispatch({ type: t.CLEAR_CATEGORY_FORM_ERRORS, errors }); } reject(error); }); }); }; -export const deleteItemCategory = id => { - return dispatch => +export const deleteItemCategory = (id) => { + return (dispatch) => new Promise((resolve, reject) => { ApiService.delete(`item_categories/${id}`) - .then(response => { + .then((response) => { dispatch({ type: t.CATEGORY_DELETE, - id + id, }); resolve(response); }) - .catch(error => { + .catch((error) => { reject(error); }); }); diff --git a/client/src/store/reducers.js b/client/src/store/reducers.js index a41666779..47cb60597 100644 --- a/client/src/store/reducers.js +++ b/client/src/store/reducers.js @@ -14,6 +14,7 @@ import financialStatements from './financialStatement/financialStatements.reduce import itemCategories from './itemCategories/itemsCategory.reducer'; import settings from './settings/settings.reducer'; import manualJournals from './manualJournals/manualJournals.reducers'; +import search from './search/search.reducer'; export default combineReducers({ authentication, @@ -30,4 +31,5 @@ export default combineReducers({ items, itemCategories, settings, + search, }); diff --git a/client/src/store/search/search.actions.js b/client/src/store/search/search.actions.js new file mode 100644 index 000000000..e9bceac84 --- /dev/null +++ b/client/src/store/search/search.actions.js @@ -0,0 +1,8 @@ +import t from 'store/types'; + +export function generalSearch(name, result) { + return { + type: t.SEARCH_SUCCESS, + result, + }; +} diff --git a/client/src/store/search/search.reducer.js b/client/src/store/search/search.reducer.js new file mode 100644 index 000000000..583f12123 --- /dev/null +++ b/client/src/store/search/search.reducer.js @@ -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 || {}, +// }; diff --git a/client/src/store/search/search.type.js b/client/src/store/search/search.type.js new file mode 100644 index 000000000..9dc5162e7 --- /dev/null +++ b/client/src/store/search/search.type.js @@ -0,0 +1,5 @@ +export default { + SEARCH_SUCCESS: 'SEARCH_SUCCESS', + SEARCH_FAILURE: 'SEARCH_FAILURE', + SEARCH_REQUEST: 'SEARCH_REQUEST', +}; diff --git a/client/src/store/types.js b/client/src/store/types.js index a157d63db..28fc76b9f 100644 --- a/client/src/store/types.js +++ b/client/src/store/types.js @@ -1,6 +1,6 @@ import authentication from './authentication/authentication.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 customFields from './customFields/customFields.types'; import customViews from './customViews/customViews.types'; @@ -13,7 +13,7 @@ import users from './users/users.types'; import financialStatements from './financialStatement/financialStatements.types'; import itemCategories from './itemCategories/itemsCategory.type'; import settings from './settings/settings.type'; - +import search from './search/search.type'; export default { ...authentication, ...accounts, @@ -30,4 +30,5 @@ export default { ...itemCategories, ...settings, ...accounting, + ...search, }; diff --git a/server/src/http/controllers/ItemCategories.js b/server/src/http/controllers/ItemCategories.js index c71b189ea..4ea416f5d 100644 --- a/server/src/http/controllers/ItemCategories.js +++ b/server/src/http/controllers/ItemCategories.js @@ -15,30 +15,40 @@ export default { router.use(JWTAuth); - router.post('/:id', + router.post( + '/:id', // permit('create', 'edit'), this.editCategory.validation, - asyncMiddleware(this.editCategory.handler)); + asyncMiddleware(this.editCategory.handler) + ); - router.post('/', + router.post( + '/', // permit('create'), this.newCategory.validation, - asyncMiddleware(this.newCategory.handler)); + asyncMiddleware(this.newCategory.handler) + ); - router.delete('/:id', + router.delete( + '/:id', // permit('create', 'edit', 'delete'), this.deleteItem.validation, - asyncMiddleware(this.deleteItem.handler)); + asyncMiddleware(this.deleteItem.handler) + ); - router.get('/:id', + router.get( + '/:id', // permit('view'), this.getCategory.validation, - asyncMiddleware(this.getCategory.handler)); + asyncMiddleware(this.getCategory.handler) + ); - router.get('/', + router.get( + '/', // permit('view'), this.getList.validation, - asyncMiddleware(this.getList.handler)); + asyncMiddleware(this.getList.handler) + ); return router; }, @@ -48,16 +58,26 @@ export default { */ newCategory: { validation: [ - check('name').exists().trim().escape(), - check('parent_category_id').optional().isNumeric().toInt(), - check('description').optional().trim().escape(), + check('name') + .exists() + .trim() + .escape(), + check('parent_category_id') + .optional({ nullable: true, checkFalsy: true }) + .isNumeric() + .toInt(), + check('description') + .optional() + .trim() + .escape() ], async handler(req, res) { const validationErrors = validationResult(req); if (!validationErrors.isEmpty()) { return res.boom.badData(null, { - code: 'validation_error', ...validationErrors, + code: 'validation_error', + ...validationErrors }); } @@ -66,20 +86,21 @@ export default { if (form.parent_category_id) { const foundParentCategory = await ItemCategory.query() - .where('id', form.parent_category_id).first(); + .where('id', form.parent_category_id) + .first(); if (!foundParentCategory) { 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({ ...form, - user_id: user.id, + user_id: user.id }); return res.status(200).send({ category }); - }, + } }, /** @@ -88,9 +109,18 @@ export default { editCategory: { validation: [ param('id').toInt(), - check('name').exists().trim().escape(), - check('parent_category_id').optional().isNumeric().toInt(), - check('description').optional().trim().escape(), + check('name') + .exists() + .trim() + .escape(), + check('parent_category_id') + .optional({ nullable: true, checkFalsy: true }) + .isNumeric() + .toInt(), + check('description') + .optional() + .trim() + .escape() ], async handler(req, res) { const { id } = req.params; @@ -98,33 +128,41 @@ export default { if (!validationErrors.isEmpty()) { return res.boom.badData(null, { - code: 'validation_error', ...validationErrors, + code: 'validation_error', + ...validationErrors }); } const form = { ...req.body }; - const itemCategory = await ItemCategory.query().where('id', id).first() + const itemCategory = await ItemCategory.query() + .where('id', id) + .first(); if (!itemCategory) { 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 - && form.parent_category_id !== itemCategory.parent_category_id) { + if ( + form.parent_category_id && + form.parent_category_id !== itemCategory.parent_category_id + ) { const foundParentCategory = await ItemCategory.query() - .where('id', form.parent_category_id).first(); + .where('id', form.parent_category_id) + .first(); if (!foundParentCategory) { 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 }); - }, + } }, /** @@ -132,20 +170,26 @@ export default { */ deleteItem: { validation: [ - param('id').exists().toInt(), + param('id') + .exists() + .toInt() ], async handler(req, res) { const { id } = req.params; - const itemCategory = await ItemCategory.query().where('id', id).first(); + const itemCategory = await ItemCategory.query() + .where('id', id) + .first(); if (!itemCategory) { 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(); - }, + } }, /** @@ -157,27 +201,25 @@ export default { const categories = await ItemCategory.query(); return res.status(200).send({ categories }); - }, + } }, /** * Retrieve details of the given category. */ getCategory: { - validation: [ - param('category_id').toInt(), - ], + validation: [param('category_id').toInt()], async handler(req, res) { const { category_id: categoryId } = req.params; const item = await ItemCategory.where('id', categoryId).fetch(); if (!item) { 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() }); - }, - }, + } + } };