From 0c6bbba64798c61bc64f09ade9de40e949e997a0 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Wed, 3 Mar 2021 13:34:18 +0200 Subject: [PATCH] feat(items): filter auto-complete results. feat(contacts): filter auto-complete results. --- .../src/api/controllers/Contacts/Contacts.ts | 26 +++++--- server/src/api/controllers/Items.ts | 63 ++++++++++--------- server/src/interfaces/Contact.ts | 7 ++- server/src/interfaces/Item.ts | 8 ++- server/src/models/Contact.js | 6 ++ .../src/services/Contacts/ContactsService.ts | 2 +- server/src/services/Items/ItemsService.ts | 8 +-- 7 files changed, 70 insertions(+), 50 deletions(-) diff --git a/server/src/api/controllers/Contacts/Contacts.ts b/server/src/api/controllers/Contacts/Contacts.ts index 7ff3ccade..5a6d79866 100644 --- a/server/src/api/controllers/Contacts/Contacts.ts +++ b/server/src/api/controllers/Contacts/Contacts.ts @@ -1,34 +1,38 @@ import { check, param, query, body, ValidationChain } from 'express-validator'; import { Router, Request, Response, NextFunction } from 'express'; -import { Inject } from 'typedi'; +import { Inject, Service } from 'typedi'; import BaseController from 'api/controllers/BaseController'; import ContactsService from 'services/Contacts/ContactsService'; +import DynamicListingService from 'services/DynamicListing/DynamicListService'; import { DATATYPES_LENGTH } from 'data/DataTypes'; -import { Service } from 'typedi'; @Service() export default class ContactsController extends BaseController { @Inject() contactsService: ContactsService; + @Inject() + dynamicListService: DynamicListingService; + /** * Express router. */ router() { const router = Router(); + router.get( + '/auto-complete', + [...this.autocompleteQuerySchema], + this.validationResult, + this.asyncMiddleware(this.autocompleteContacts.bind(this)), + this.dynamicListService.handlerErrorsToResponse + ); router.get( '/:id', [param('id').exists().isNumeric().toInt()], this.validationResult, this.asyncMiddleware(this.getContact.bind(this)) ); - router.get( - '/auto-complete', - [...this.autocompleteQuerySchema], - this.validationResult, - this.asyncMiddleware(this.autocompleteContacts.bind(this)) - ); return router; } @@ -79,11 +83,13 @@ export default class ContactsController extends BaseController { const filter = { filterRoles: [], sortOrder: 'asc', - columnSortBy: 'created_at', + columnSortBy: 'display_name', limit: 10, ...this.matchedQueryData(req), }; - + if (filter.stringifiedFilterRoles) { + filter.filterRoles = JSON.parse(filter.stringifiedFilterRoles); + } try { const contacts = await this.contactsService.autocompleteContacts( tenantId, diff --git a/server/src/api/controllers/Items.ts b/server/src/api/controllers/Items.ts index a18f55c41..b029e8447 100644 --- a/server/src/api/controllers/Items.ts +++ b/server/src/api/controllers/Items.ts @@ -216,38 +216,11 @@ export default class ItemsController extends BaseController { query('stringified_filter_roles').optional().isJSON(), query('limit').optional().isNumeric().toInt(), + + query('keyword').optional().isString().trim().escape(), ]; } - /** - * Auto-complete list. - * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async autocompleteList(req: Request, res: Response, next: NextFunction) { - const { tenantId } = req; - const filter = { - filterRoles: [], - sortOrder: 'asc', - columnSortBy: 'created_at', - limit: 10, - ...this.matchedQueryData(req), - }; - - try { - const items = await this.itemsService.autocompleteItems( - tenantId, - filter - ); - return res.status(200).send({ - items, - }); - } catch (error) { - next(error); - } - } - /** * Stores the given item details to the storage. * @param {Request} req @@ -410,6 +383,38 @@ export default class ItemsController extends BaseController { } } + /** + * Auto-complete list. + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next + */ + async autocompleteList(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; + const filter = { + filterRoles: [], + sortOrder: 'asc', + columnSortBy: 'name', + limit: 10, + keyword: '', + ...this.matchedQueryData(req), + }; + if (filter.stringifiedFilterRoles) { + filter.filterRoles = JSON.parse(filter.stringifiedFilterRoles); + } + try { + const items = await this.itemsService.autocompleteItems( + tenantId, + filter + ); + return res.status(200).send({ + items, + }); + } catch (error) { + next(error); + } + } + /** * Deletes items in bulk. * @param {Request} req diff --git a/server/src/interfaces/Contact.ts b/server/src/interfaces/Contact.ts index a8519819c..6a6c0e279 100644 --- a/server/src/interfaces/Contact.ts +++ b/server/src/interfaces/Contact.ts @@ -1,7 +1,5 @@ -// Contact Interfaces. - -import { IDynamicListFilter } from "./DynamicFilter"; +import { IFilterRole } from "./DynamicFilter"; // ---------------------------------- export interface IContactAddress { @@ -208,6 +206,9 @@ export interface ICustomersFilter extends IDynamicListFilter { export interface IContactsAutoCompleteFilter { limit: number, keyword: string, + filterRoles?: IFilterRole[]; + columnSortBy: string; + sortOrder: string; } export interface IContactAutoCompleteItem { diff --git a/server/src/interfaces/Item.ts b/server/src/interfaces/Item.ts index 27b26b743..ed2c0d147 100644 --- a/server/src/interfaces/Item.ts +++ b/server/src/interfaces/Item.ts @@ -1,4 +1,4 @@ -import { IDynamicListFilter } from 'interfaces/DynamicFilter'; +import { IFilterRole } from 'interfaces/DynamicFilter'; export interface IItem{ id: number, @@ -72,7 +72,7 @@ export interface IItemsService { itemsList(tenantId: number, itemsFilter: IItemsFilter): Promise<{items: IItem[]}>; } -export interface IItemsFilter extends IDynamicListFilter { +export interface IItemsFilter extends IDynamicListFilterDTO { stringifiedFilterRoles?: string, page: number, pageSize: number, @@ -81,5 +81,7 @@ export interface IItemsFilter extends IDynamicListFilter { export interface IItemsAutoCompleteFilter { limit: number, keyword: string, - + filterRoles?: IFilterRole[]; + columnSortBy: string; + sortOrder: string; } \ No newline at end of file diff --git a/server/src/models/Contact.js b/server/src/models/Contact.js index fb4953ef5..fe5166490 100644 --- a/server/src/models/Contact.js +++ b/server/src/models/Contact.js @@ -97,6 +97,12 @@ export default class Contact extends TenantModel { static get fields() { return { + contact_service: { + column: 'contact_service', + }, + display_name: { + column: 'display_name', + }, created_at: { column: 'created_at', } diff --git a/server/src/services/Contacts/ContactsService.ts b/server/src/services/Contacts/ContactsService.ts index e152fa137..938af5f46 100644 --- a/server/src/services/Contacts/ContactsService.ts +++ b/server/src/services/Contacts/ContactsService.ts @@ -201,7 +201,7 @@ export default class ContactsService { // Retrieve contacts list by the given query. const contacts = await Contact.query().onBuild((builder) => { if (contactsFilter.keyword) { - builder.where('display_name', 'LIKE', contactsFilter.keyword); + builder.where('display_name', 'LIKE', `%${contactsFilter.keyword}%`); } dynamicList.buildQuery()(builder); builder.limit(contactsFilter.limit); diff --git a/server/src/services/Items/ItemsService.ts b/server/src/services/Items/ItemsService.ts index 8b9b76044..d3046fe8c 100644 --- a/server/src/services/Items/ItemsService.ts +++ b/server/src/services/Items/ItemsService.ts @@ -523,14 +523,14 @@ export default class ItemsService implements IItemsService { dynamicFilter.buildQuery()(builder); builder.limit(itemsFilter.limit); - }); - // const autocompleteItems = this.transformAutoCompleteItems(items); + if (itemsFilter.keyword) { + builder.where('name', 'LIKE', `%${itemsFilter.keyword}%`); + } + }); return items; } - // transformAutoCompleteItems(item) - /** * Validates the given item or items have no associated invoices or bills. * @param {number} tenantId - Tenant id.