import './Products.html'; import Batches from "../api/Batch"; let QUERY_LIMIT = 100; let QUERY_LIMIT_INCREMENT = 100; let PREFIX = "Products."; Tracker.autorun(function() { Meteor.subscribe("products"); Meteor.subscribe("productTags"); Meteor.subscribe("measures"); }); Template.Products.onCreated(function() { Session.set(PREFIX + "displayNew", false); Session.set(PREFIX + "showHidden", false); Session.set(PREFIX + "queryLimit", QUERY_LIMIT); }); Template.Products.onRendered(function() { $(".tableContainer").mCustomScrollbar({ scrollButtons: {enable:true}, theme: "light-thick", scrollbarPosition: "outside", scrollEasing: "linear" }); }); Template.Products.helpers({ displayNew: function() { return Session.get(PREFIX + "displayNew"); }, products: function() { let skipCount = Session.get(PREFIX + 'skipCount') || 0; let query = Session.get(PREFIX + 'searchQuery'); let dbQuery = []; if(query) { _.each(_.keys(query), function(key) { if(_.isFunction(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key](); else if(_.isObject(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key]; //Will look something like: {$in: [xxx,xxx,xxx]} else if(_.isNumber(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key]; else { //dbQuery[key] = {$regex: query[key], $options: 'i'}; let searchValue = query[key]; let searches = searchValue && searchValue.length > 0 ? searchValue.split(/\s+/) : undefined; for(let search of searches) { dbQuery.push({[key]: {$regex: '\\b' + search, $options: 'i'}}); } } }) } if(!Session.get(PREFIX + "showHidden")) { //Ignore any hidden elements by showing those not hidden, or those without the hidden field. dbQuery.push({$or: [{hidden: false}, {hidden: {$exists:false}}]}); } dbQuery = dbQuery.length > 0 ? {$and: dbQuery} : {}; Session.set(PREFIX + 'productCount', Meteor.collections.Products.find(dbQuery).count()); //Always get a full count. //console.log("dbQuery=" + JSON.stringify(dbQuery)); //console.log("Result Count: " + Meteor.collections.Products.find(dbQuery).count()); return Meteor.collections.Products.find(dbQuery, {limit: Session.get(PREFIX + "queryLimit"), skip: skipCount, sort: {name: 1}}); }, disableLoadMore: function() { return Session.get(PREFIX + 'productCount') - (Session.get(PREFIX + 'skipCount') || 0) - Session.get(PREFIX + "queryLimit") <= 0; } }); Template.Products.events({ 'click .loadMoreLink': function(event, template) { event.preventDefault(); Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT); }, 'click .newButton': function(event, template) { if(template.$('.newButton').hasClass('active')) { Session.set(PREFIX + 'displayNew', false); } else { Session.set(PREFIX + 'displayNew', true); Session.set(PREFIX + "editedId", undefined); //Clear the edited product so that only one editor is open at a time. Session.set(PREFIX + "convertedProduct", undefined); //Clear the converted product so that only one editor is open at a time. } template.$('.newButton').toggleClass('active'); }, 'change input[name="showHidden"]': function(event, template) { //console.log("changed " + $(event.target).prop('checked')); Session.set(PREFIX + "showHidden", $(event.target).prop('checked')); } }); Template.ProductSearch.events({ "keyup .searchInput": _.throttle(function(event, template) { let searchQuery = Session.get(PREFIX + 'searchQuery') || {}; let searchFields = Session.get(PREFIX + 'searchFields') || {}; let searchValue = template.$('.searchInput').val(); if(searchValue) { if(this.number) searchValue = parseFloat(searchValue); if(this.collection) { let ids = Meteor.collections[this.collection].find({[this.collectionQueryColumnName]: {$regex: searchValue, $options: 'i'}}, {fields: {[this.collectionResultColumnName]: 1}}).fetch(); //Convert the ids to an array of ids instead of an array of objects containing an id. for(let i = 0; i < ids.length; i++) {ids[i] = ids[i]._id;} searchQuery[this.columnName] = {$in: ids}; searchFields[this.columnName] = searchValue; } else { searchFields[this.columnName] = searchQuery[this.columnName] = searchValue; } } else { //Remove columns from the search query whose values are empty so we don't bother the database with them. delete searchQuery[this.columnName]; delete searchFields[this.columnName]; } Session.set(PREFIX + 'searchQuery', searchQuery); Session.set(PREFIX + 'searchFields', searchFields); Session.set(PREFIX + 'skipCount', 0); //Reset the paging of the results. }, 500) }); Template.ProductSearch.helpers({ searchValue: function() { let searchFields = Session.get(PREFIX + 'searchFields'); return (searchFields && searchFields[this.columnName]) ? searchFields[this.columnName] : ''; } }); Template.Product.helpers({ measures: function() { let result = ""; if(this.measures && this.measures.length > 0) { let measureNames = []; for(let i = 0; i < this.measures.length; i++) { let measureObject = Meteor.collections.Measures.findOne(this.measures[i]); if(measureObject && measureObject.name) measureNames.push(measureObject.name); } result = measureNames.join(", "); } return result; }, aliases: function() { return this.aliases.join(', '); }, tags: function() { let result = ""; if(this.tags && this.tags.length > 0) { let tagNames = []; for(let i = 0; i < this.tags.length; i++) { let obj = Meteor.collections.ProductTags.findOne(this.tags[i]); if(obj && obj.name) tagNames.push(obj.name); } result = tagNames.join(", "); } return result; }, editing: function() { let editedId = Session.get(PREFIX + "editedId"); return editedId == this._id; }, converting: function() { let convertedProduct = Session.get(PREFIX + "convertedProduct"); return convertedProduct == this._id; }, getRowClass: function() { return this.hidden ? "hidden" : this.deactivated ? "deactivated" : ""; } }); Template.Product.events({ "click .actionEdit": function(event, template) { Session.set(PREFIX + "editedId", this._id); Session.set(PREFIX + 'displayNew', false); //Ensure the new editor is closed. Session.set(PREFIX + "convertedProduct", undefined); //Clear the converted product so that only one editor is open at a time. template.parentTemplate().$('.newButton').removeClass('active'); }, "click .actionDeactivate": function(event, template) { Meteor.call('deactivateProduct', this._id, function(error, result) { if(error) sAlert.error(error); else sAlert.success("Product Deactivated"); }); }, 'click .actionActivate': function(event, template) { Meteor.call('reactivateProduct', this._id, function(error, result) { if(error) sAlert.error(error); else sAlert.success("Product Reactivated"); }); }, "click .actionShow": function(event, template) { Meteor.call('showProduct', this._id, function(error, result) { if(error) sAlert.error(error); else sAlert.success("Product Visibility Enabled"); }); }, "click .actionConvert": function(event, template) { Session.set(PREFIX + "convertedProduct", this._id); Session.set(PREFIX + 'displayNew', false); //Ensure the new editor is closed. Session.set(PREFIX + "editedId", undefined); //Clear the edited product so that only one editor is open at a time. template.$('.newButton').removeClass('active'); }, 'click .actionHide': function(event, template) { Meteor.call('hideProduct', this._id, function(error, result) { if(error) sAlert.error(error); else sAlert.success("Product Visibility Disabled"); }); } }); Template.ProductEditor.onRendered(function() { this.$(".productTagsEditor").select2(); this.$(".productAliasesEditor").select2({tags: true, tokenSeparators: [';', '.']}); this.$(".productMeasuresEditor").select2(); }); Template.ProductEditor.helpers({ measures: function() { return Meteor.collections.Measures.find({}); }, measureSelected: function() { let measure = this; let product = Template.parentData(); return product.measures && product.measures.includes(measure._id) ? "selected" : ""; }, aliases: function() { return this.aliases; }, tags: function() { return Meteor.collections.ProductTags.find({}); }, tagSelected: function() { let tag = this; let product = Template.parentData(); return product.tags && product.tags.includes(tag._id) ? "selected" : ""; } }); Template.ProductEditor.events({ "click .editorCancel": function(event, template) { Session.set(PREFIX + "editedId", undefined); Session.set(PREFIX + 'displayNew', false); template.parentTemplate().$('.newButton').removeClass('active'); }, "click .editorApply": function(event, template) { let name = template.$("input[name='name']").val().trim(); let tags = template.$(".productTagsEditor").select2('data'); let aliases = template.$(".productAliasesEditor").select2('data'); let measures = template.$(".productMeasuresEditor").select2('data'); tags = tags.map((n)=>n.id); aliases = aliases.map((n)=>n.id); measures = measures.map((n)=>n.id); if(Session.get(PREFIX + 'displayNew')) { Meteor.call("createProduct", name, tags, aliases, measures, function(error, result) { if(error) sAlert.error(error); else { sAlert.success("Product created."); Session.set(PREFIX + 'displayNew', false); template.parentTemplate().$('.newButton').removeClass('active'); } }); } else { Meteor.call("updateProduct", this._id, name, tags, aliases, measures, function(error, result) { if(error) sAlert.error(error); else { sAlert.success("Product updated."); Session.set(PREFIX + "editedId", undefined); template.parentTemplate().$('.newButton').removeClass('active'); } }); } } }); Template.ConvertProduct.onCreated(function() { this.selectedProduct = new ReactiveVar(); }); Template.ConvertProduct.onRendered(function() { this.$('[name="product"]').buildCombo({cursor: Meteor.collections.Products.find({$or: [{hidden: false}, {hidden: {$exists:false}}]}), selection: this.selectedProduct, textAttr: 'name', listClass: 'comboList', getClasses: function(data) { return (data && data.deactivated) ? "deactivated" : ""; }}); }); Template.ConvertProduct.events({ "click .editorCancel": function(event, template) { Session.set(PREFIX + "editedId", undefined); Session.set(PREFIX + "convertedProduct", undefined); Session.set(PREFIX + 'displayNew', false); template.parentTemplate().$('.newButton').removeClass('active'); }, "click .editorApply": function(event, template) { let productId = template.selectedProduct.get()._id; Meteor.call("convertProduct", this._id, productId, function(error, result) { if(error) sAlert.error(error); else { sAlert.success("Sales of this product were converted."); Session.set(PREFIX + "editedId", undefined); Session.set(PREFIX + "convertedProduct", undefined); Session.set(PREFIX + 'displayNew', false); template.parentTemplate().$('.newButton').removeClass('active'); } }); } });