Merge branch '2112-order_catalog_improvements' of verdnatura/salix into dev
gitea/salix/dev This commit looks good
Details
gitea/salix/dev This commit looks good
Details
This commit is contained in:
commit
aece3e8788
|
@ -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]',
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue