Merge branch '2112-order_catalog_improvements' of verdnatura/salix into dev
gitea/salix/dev This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2020-02-19 13:48:00 +00:00 committed by Gitea
commit aece3e8788
7 changed files with 179 additions and 72 deletions

View File

@ -620,9 +620,9 @@ export default {
orderCatalog: {
plantRealmButton: 'vn-order-catalog > vn-side-menu vn-icon[icon="icon-plant"]',
type: 'vn-autocomplete[data="$ctrl.itemTypes"]',
itemId: 'vn-order-catalog > vn-side-menu vn-textfield[ng-model="$ctrl.itemId"]',
itemTagValue: 'vn-order-catalog > vn-side-menu vn-datalist[ng-model="$ctrl.value"]',
openTagSearch: 'vn-order-catalog > vn-side-menu > div > vn-vertical > vn-datalist[ng-model="$ctrl.value"] .append i',
itemId: 'vn-order-catalog > vn-side-menu vn-textfield[vn-id="itemId"]',
itemTagValue: 'vn-order-catalog > vn-side-menu vn-datalist[vn-id="search"]',
openTagSearch: 'vn-order-catalog > vn-side-menu > div > vn-vertical > vn-datalist[vn-id="search"] .append i',
tag: 'vn-order-catalog-search-panel vn-autocomplete[ng-model="filter.tagFk"]',
tagValue: 'vn-order-catalog-search-panel vn-textfield[ng-model="filter.value"]',
searchTagButton: 'vn-order-catalog-search-panel button[type=submit]',

View File

@ -1,13 +1,15 @@
<div class="vn-pa-lg" style="min-width: 10em">
<form ng-submit="$ctrl.onSearch()">
<form name="form" ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-autocomplete
vn-one
label="Tag"
ng-model="filter.tagFk"
selection="filter.tagSelection"
url="Tags"
show-field="name"
value-field="id">
value-field="id"
required="true">
<tpl-item>{{name}}</tpl-item>
</vn-autocomplete>
</vn-horizontal>
@ -15,7 +17,8 @@
<vn-textfield
vn-one
label="Value"
ng-model="filter.value">
ng-model="filter.value"
required="true">
</vn-textfield>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">

View File

@ -77,10 +77,9 @@
</div>
</vn-vertical>
<vn-vertical class="input vn-pt-md">
<vn-textfield
<vn-textfield vn-id="itemId"
ng-keyUp="$ctrl.onSearchById($event)"
label="Item id"
ng-model="$ctrl.itemId">
label="Item id">
<prepend>
<vn-icon icon="icon-item"></vn-icon>
</prepend>
@ -89,7 +88,6 @@
<vn-datalist vn-one
vn-id="search"
data="$ctrl.tagValues"
ng-model="$ctrl.value"
ng-keyUp="$ctrl.onSearchByTag($event)"
show-field="value"
value-field="value"
@ -115,6 +113,14 @@
</vn-order-catalog-search-panel>
</vn-popover>
<div class="chips">
<vn-chip
ng-if="$ctrl.itemId"
removable="true"
translate-attr="{title: 'Item'}"
on-remove="$ctrl.itemId = null"
class="colored">
<span>Id: {{$ctrl.itemId}}</span>
</vn-chip>
<vn-chip
ng-if="category.selection"
removable="true"
@ -137,7 +143,17 @@
translate-attr="{title: 'Tag'}"
on-remove="$ctrl.remove($index)"
class="colored">
<span translate>{{::tag.value}}</span>
<div>
<span ng-if="::tag.tagFk">
<span translate>
{{::tag.tagSelection.name}}
</span>
<span ng-if="::tag.value">: </span>
</span>
<span translate ng-if="::tag.value">
"{{::tag.value}}"
</span>
</div>
</vn-chip>
</div>
</vn-side-menu>

View File

@ -10,7 +10,7 @@ class Controller {
this.$compile = $compile;
this.$transitions = $transitions;
this.itemTypes = [];
this.tags = [];
this._tags = [];
// Static autocomplete data
this.orderWays = [
@ -52,11 +52,17 @@ class Controller {
if (!value) return;
this.$.$applyAsync(() => {
if (this.$stateParams.itemId)
this.itemId = parseInt(this.$stateParams.itemId);
if (this.$stateParams.categoryId)
this.categoryId = this.$stateParams.categoryId;
this.categoryId = parseInt(this.$stateParams.categoryId);
if (this.$stateParams.typeId)
this.typeId = this.$stateParams.typeId;
this.typeId = parseInt(this.$stateParams.typeId);
if (this.$stateParams.tags)
this.tags = JSON.parse(this.$stateParams.tags);
});
}
@ -109,6 +115,30 @@ class Controller {
this.applyFilters();
}
get itemId() {
return this._itemId;
}
set itemId(value) {
this._itemId = value;
this.updateStateParams();
this.applyFilters();
}
get tags() {
return this._tags;
}
set tags(value) {
this._tags = value;
this.updateStateParams();
if (value.length)
this.applyFilters();
}
/**
* Get order way ASC/DESC
*/
@ -169,23 +199,36 @@ class Controller {
this.itemTypes = res.data);
}
/**
* Search by item id filter
* @param {object} event
*/
onSearchById(event) {
const hasValue = this.tags.length > 0 || this.itemId || this.typeId;
if (event.key === 'Enter' && hasValue)
this.applyFilters();
const value = this.$.itemId.value;
if (event.key === 'Enter' && value) {
this.itemId = value;
this.$.itemId.value = null;
}
}
/**
* Search by tag value
* @param {object} event
*/
onSearchByTag(event) {
if (event.key !== 'Enter' || !this.value) return;
const value = this.$.search.value;
if (event.key !== 'Enter' || !value) return;
this.tags.push({
value: this.value,
value: value,
});
this.$.search.value = null;
this.updateStateParams();
this.applyFilters();
}
remove(index) {
this.tags.splice(index, 1);
this.updateStateParams();
if (this.tags.length >= 0 || this.itemId || this.typeId)
this.applyFilters();
@ -225,6 +268,7 @@ class Controller {
onPanelSubmit(filter) {
this.$.popover.hide();
this.tags.push(filter);
this.updateStateParams();
this.applyFilters();
}
@ -234,13 +278,36 @@ class Controller {
updateStateParams() {
const params = {};
params.categoryId = undefined;
if (this.categoryId)
params.categoryId = this.categoryId;
else params.categoryId = undefined;
params.typeId = undefined;
if (this.typeId)
params.typeId = this.typeId;
else params.typeId = undefined;
params.itemId = undefined;
if (this.itemId)
params.itemId = this.itemId;
params.tags = undefined;
if (this.tags.length) {
const tags = [];
for (let tag of this.tags) {
const tagParam = {value: tag.value};
if (tag.tagSelection) {
tagParam.tagFk = tag.tagFk;
tagParam.tagSelection = {
name: tag.tagSelection.name
};
}
tags.push(tagParam);
}
params.tags = JSON.stringify(tags);
}
this.$state.go(this.$state.current.name, params);
}

View File

@ -15,6 +15,7 @@ describe('Order', () => {
$scope = $rootScope.$new();
$scope.model = crudModel;
$scope.search = {};
$scope.itemId = {};
$state = _$state_;
$state.params.categoryId = 1;
$state.params.typeId = 2;
@ -37,8 +38,9 @@ describe('Order', () => {
describe('items() setter', () => {
it(`should return an object with order params`, () => {
spyOn(controller, 'buildTagsFilter');
spyOn(controller, 'buildOrderFilter').and.callThrough();
jest.spyOn(controller, 'buildTagsFilter');
jest.spyOn(controller, 'buildOrderFilter');
const expectedResult = [{field: 'showOrder, price', name: 'Color and price'}];
const items = [{id: 1, name: 'My Item', tags: [
{tagFk: 4, name: 'Length'},
@ -55,14 +57,16 @@ describe('Order', () => {
describe('categoryId() setter', () => {
it(`should set category property to null, call updateStateParams() method and not call applyFilters()`, () => {
spyOn(controller, 'updateStateParams');
jest.spyOn(controller, 'updateStateParams');
controller.categoryId = null;
expect(controller.updateStateParams).toHaveBeenCalledWith();
});
it(`should set category property and then call updateStateParams() and applyFilters() methods`, () => {
spyOn(controller, 'updateStateParams');
jest.spyOn(controller, 'updateStateParams');
controller.categoryId = 2;
expect(controller.updateStateParams).toHaveBeenCalledWith();
@ -87,8 +91,9 @@ describe('Order', () => {
describe('typeId() setter', () => {
it(`should set type property to null, call updateStateParams() method and not call applyFilters()`, () => {
spyOn(controller, 'updateStateParams');
spyOn(controller, 'applyFilters');
jest.spyOn(controller, 'updateStateParams');
jest.spyOn(controller, 'applyFilters');
controller.typeId = null;
expect(controller.updateStateParams).toHaveBeenCalledWith();
@ -96,8 +101,9 @@ describe('Order', () => {
});
it(`should set category property and then call updateStateParams() and applyFilters() methods`, () => {
spyOn(controller, 'updateStateParams');
spyOn(controller, 'applyFilters');
jest.spyOn(controller, 'updateStateParams');
jest.spyOn(controller, 'applyFilters');
controller.typeId = 2;
expect(controller.updateStateParams).toHaveBeenCalledWith();
@ -105,21 +111,46 @@ describe('Order', () => {
});
});
describe('itemId() setter', () => {
it(`should set itemId property and then call updateStateParams() and applyFilters() methods`, () => {
jest.spyOn(controller, 'updateStateParams');
jest.spyOn(controller, 'applyFilters');
controller.itemId = 1;
expect(controller.updateStateParams).toHaveBeenCalledWith();
expect(controller.applyFilters).toHaveBeenCalledWith();
});
});
describe('tags() setter', () => {
it(`should set tags property and then call updateStateParams() and applyFilters() methods`, () => {
jest.spyOn(controller, 'updateStateParams');
jest.spyOn(controller, 'applyFilters');
controller.tags = [{tagFk: 11, value: 'Brown'}];
expect(controller.updateStateParams).toHaveBeenCalledWith();
expect(controller.applyFilters).toHaveBeenCalledWith();
});
});
describe('onSearchByTag()', () => {
it(`should not add a new tag if the event key code doesn't equals to 'Enter'`, () => {
spyOn(controller, 'applyFilters');
jest.spyOn(controller, 'applyFilters');
controller.order = {id: 4};
controller.value = 'Color';
controller.$.search.value = 'Brown';
controller.onSearchByTag({key: 'Tab'});
expect(controller.applyFilters).not.toHaveBeenCalledWith();
});
it(`should add a new tag if the event key code equals to 'Enter' an then call applyFilters()`, () => {
spyOn(controller, 'applyFilters');
controller.order = {id: 4};
controller.value = 'Color';
jest.spyOn(controller, 'applyFilters');
controller.order = {id: 4};
controller.$.search.value = 'Brown';
controller.onSearchByTag({key: 'Enter'});
expect(controller.applyFilters).toHaveBeenCalledWith();
@ -128,17 +159,18 @@ describe('Order', () => {
describe('onSearchById()', () => {
it(`should not filter by id if the event key code doesn't equals to 'Enter'`, () => {
spyOn(controller, 'applyFilters');
controller.itemId = 1;
jest.spyOn(controller, 'applyFilters');
controller.$.itemId.value = 1;
controller.onSearchById({key: 'Tab'});
expect(controller.applyFilters).not.toHaveBeenCalledWith();
});
it(`should filter by id if the event key code equals to 'Enter' an then call applyFilters()`, () => {
spyOn(controller, 'applyFilters');
controller.itemId = 1;
jest.spyOn(controller, 'applyFilters');
controller.$.itemId.value = 1;
controller.onSearchById({key: 'Enter'});
expect(controller.applyFilters).toHaveBeenCalledWith();
@ -147,14 +179,14 @@ describe('Order', () => {
describe('applyFilters()', () => {
it(`should call model applyFilter() method with a new filter`, () => {
let model = controller.$.model;
spyOn(model, 'applyFilter');
jest.spyOn(controller.$.model, 'applyFilter');
controller._categoryId = 2;
controller._typeId = 4;
controller.applyFilters();
expect(model.applyFilter).toHaveBeenCalledWith(
expect(controller.$.model.applyFilter).toHaveBeenCalledWith(
{where: {categoryFk: 2, typeFk: 4}},
{orderFk: 4, orderBy: controller.getOrderBy(), tags: []});
});
@ -162,7 +194,8 @@ describe('Order', () => {
describe('remove()', () => {
it(`should remove a tag from tags property`, () => {
spyOn(controller, 'applyFilters');
jest.spyOn(controller, 'applyFilters');
controller.tags = [{tagFk: 1, value: 'Blue'}, {tagFk: 2, value: '70'}];
controller.remove(0);
@ -172,7 +205,8 @@ describe('Order', () => {
});
it(`should remove a tag from tags property and call applyFilters() if there's no more tags`, () => {
spyOn(controller, 'applyFilters');
jest.spyOn(controller, 'applyFilters');
controller._categoryId = 1;
controller._typeId = 1;
controller.tags = [{tagFk: 1, value: 'Blue'}];
@ -185,10 +219,19 @@ describe('Order', () => {
describe('updateStateParams()', () => {
it(`should call state go() method passing category and type state params`, () => {
spyOn(controller.$state, 'go');
jest.spyOn(controller.$state, 'go');
controller._categoryId = 2;
controller._typeId = 4;
let result = {categoryId: 2, typeId: 4};
controller._itemId = 1;
controller._tags = [
{tagFk: 11, value: 'Precission', tagSelection: {name: 'Category'}}
];
const tags = JSON.stringify([{
value: 'Precission',
tagFk: 11, tagSelection: {name: 'Category'}}
]);
let result = {categoryId: 2, typeId: 4, itemId: 1, tags: tags};
controller.updateStateParams();
expect(controller.$state.go).toHaveBeenCalledWith('my.current.state', result);
@ -212,13 +255,15 @@ describe('Order', () => {
describe('applyOrder()', () => {
it(`should apply order param to model calling getOrderBy()`, () => {
jest.spyOn(controller, 'getOrderBy');
jest.spyOn(controller.$.model, 'addFilter');
controller.field = 'relevancy DESC, name';
controller.way = 'ASC';
controller._categoryId = 1;
controller._typeId = 1;
let expectedOrder = {orderBy: controller.getOrderBy()};
spyOn(controller, 'getOrderBy').and.callThrough();
spyOn(controller.$.model, 'addFilter');
controller.applyOrder();
expect(controller.getOrderBy).toHaveBeenCalledWith();

View File

@ -73,30 +73,6 @@ class Controller extends Component {
addQuantity(price) {
if (this.total + price.grouping <= this.max)
price.quantity += price.grouping;
this.validate();
}
validate() {
/*
this.$timeout(() => {
this.calculateTotal();
let inputs = this.$element[0].querySelectorAll('vn-input-number[name="quantity"] div.infix:not(.validated)');
inputs.forEach(input => {
if (this.total > this.item.available)
input.classList.add('invalid');
else
input.classList.remove('invalid');
});
let wrongInputs = this.$element[0].querySelectorAll('vn-input-number[name="quantity"] div.infix.invalid');
if (wrongInputs.length > 0)
this.$element[0].querySelector('vn-vertical.prices').classList.add('invalid');
else
this.$element[0].querySelector('vn-vertical.prices').classList.remove('invalid');
});
*/
}
getFilledLines() {

View File

@ -41,7 +41,7 @@
"order": "$ctrl.order"
}
}, {
"url": "/catalog?categoryId&typeId",
"url": "/catalog?categoryId&typeId&itemId&tags",
"state": "order.card.catalog",
"component": "vn-order-catalog",
"description": "Catalog",