diff --git a/imports/plugins/included/product-admin/client/components/productAdmin.js b/imports/plugins/included/product-admin/client/components/productAdmin.js index 1d34cf290c3..264d6c57952 100644 --- a/imports/plugins/included/product-admin/client/components/productAdmin.js +++ b/imports/plugins/included/product-admin/client/components/productAdmin.js @@ -35,8 +35,8 @@ class ProductAdmin extends Component { } handleToggleVisibility = () => { - if (this.props.onFieldChange) { - this.props.onFieldChange("isVisible", !this.product.isVisible); + if (this.props.onProductFieldSave) { + this.props.onProductFieldSave(this.product._id, "isVisible", !this.product.isVisible); } } diff --git a/imports/plugins/included/product-variant/client/templates/products/productDetail/productDetail.js b/imports/plugins/included/product-variant/client/templates/products/productDetail/productDetail.js index eed052e7dda..8c54843135c 100644 --- a/imports/plugins/included/product-variant/client/templates/products/productDetail/productDetail.js +++ b/imports/plugins/included/product-variant/client/templates/products/productDetail/productDetail.js @@ -10,6 +10,7 @@ import { Template } from "meteor/templating"; import { Button, EditButton } from "/imports/plugins/core/ui/client/components"; import { PublishContainer } from "/imports/plugins/core/revisions"; import { ProductDetailContainer } from "/imports/plugins/included/product-detail-simple/client/containers"; +import { isRevisionControlEnabled } from "/imports/plugins/core/revisions/lib/api"; Template.productDetail.onCreated(function () { this.state = new ReactiveDict(); @@ -574,45 +575,50 @@ Template.productDetailDashboardControls.helpers({ */ Template.productDetailDashboardControls.events({ "click [data-event-action=publishProduct]": function (event, template) { - let errorMsg = ""; const instance = Template.instance(); const self = instance.state.get("product") || {}; - if (!self.title) { - errorMsg += `${i18next.t("error.isRequired", { field: i18next.t("productDetailEdit.title") })} `; - template.$(".title-edit-input").focus(); - } - const variants = ReactionProduct.getVariants(self._id); - variants.forEach((variant, index) => { - if (!variant.title) { - errorMsg += - `${i18next.t("error.variantFieldIsRequired", { field: i18next.t("productVariant.title"), number: index + 1 })} `; + + if (isRevisionControlEnabled()) { + Meteor.call("products/updateProductField", self._id, "isVisible", !self.isVisible); + } else { + let errorMsg = ""; + if (!self.title) { + errorMsg += `${i18next.t("error.isRequired", { field: i18next.t("productDetailEdit.title") })} `; + template.$(".title-edit-input").focus(); } - // if top variant has children, it is not necessary to check its price - if (variant.ancestors.length === 1 && !ReactionProduct.checkChildVariants(variant._id) || - variant.ancestors.length !== 1) { - if (!variant.price) { + const variants = ReactionProduct.getVariants(self._id); + variants.forEach((variant, index) => { + if (!variant.title) { errorMsg += - `${i18next.t("error.variantFieldIsRequired", { field: i18next.t("productVariant.price"), number: index + 1 })} `; + `${i18next.t("error.variantFieldIsRequired", { field: i18next.t("productVariant.title"), number: index + 1 })} `; } - } - }); - if (errorMsg.length > 0) { - Alerts.inline(errorMsg, "warning", { - placement: "productManagement", - i18nKey: "productDetail.errorMsg" - }); - } else { - Meteor.call("products/publishProduct", self._id, function (error) { - if (error) { - return Alerts.inline(error.reason, "error", { - placement: "productManagement", - id: self._id, - i18nKey: "productDetail.errorMsg" - }); + // if top variant has children, it is not necessary to check its price + if (variant.ancestors.length === 1 && !ReactionProduct.checkChildVariants(variant._id) || + variant.ancestors.length !== 1) { + if (!variant.price) { + errorMsg += + `${i18next.t("error.variantFieldIsRequired", { field: i18next.t("productVariant.price"), number: index + 1 })} `; + } } - - return true; }); + if (errorMsg.length > 0) { + Alerts.inline(errorMsg, "warning", { + placement: "productManagement", + i18nKey: "productDetail.errorMsg" + }); + } else { + Meteor.call("products/publishProduct", self._id, function (error) { + if (error) { + return Alerts.inline(error.reason, "error", { + placement: "productManagement", + id: self._id, + i18nKey: "productDetail.errorMsg" + }); + } + + return true; + }); + } } } }); diff --git a/imports/plugins/included/product-variant/client/templates/products/productGrid/item.js b/imports/plugins/included/product-variant/client/templates/products/productGrid/item.js index 93c5e7c7c7c..3a88dc8d4e9 100644 --- a/imports/plugins/included/product-variant/client/templates/products/productGrid/item.js +++ b/imports/plugins/included/product-variant/client/templates/products/productGrid/item.js @@ -8,6 +8,7 @@ import { Reaction } from "/client/api"; import Logger from "/client/modules/logger"; import { ReactionProduct } from "/lib/api"; import { Media } from "/lib/collections"; +import { isRevisionControlEnabled } from "/imports/plugins/core/revisions/lib/api"; /** * productGridItems helpers @@ -49,7 +50,11 @@ Template.productGridItems.helpers({ $checkbox.prop("checked", true).trigger("change"); }, onPublishButtonClick() { - ReactionProduct.publishProduct(instance.data); + if (isRevisionControlEnabled()) { + Meteor.call("products/updateProductField", instance.data._id, "isVisible", !instance.data.isVisible); + } else { + ReactionProduct.publishProduct(instance.data); + } } }; }, diff --git a/imports/plugins/included/product-variant/client/templates/products/productSettings/productSettings.js b/imports/plugins/included/product-variant/client/templates/products/productSettings/productSettings.js index 2f7983f0306..74496c97d84 100644 --- a/imports/plugins/included/product-variant/client/templates/products/productSettings/productSettings.js +++ b/imports/plugins/included/product-variant/client/templates/products/productSettings/productSettings.js @@ -4,6 +4,8 @@ import Logger from "/client/modules/logger"; import { ReactionProduct } from "/lib/api"; import { Media, Products } from "/lib/collections"; import { PublishContainer } from "/imports/plugins/core/revisions"; +import { isRevisionControlEnabled } from "/imports/plugins/core/revisions/lib/api"; +import { applyProductRevision } from "/lib/api/products"; Template.productSettings.onCreated(function () { this.state = new ReactiveDict(); @@ -19,18 +21,16 @@ Template.productSettings.onCreated(function () { const productIds = currentData.products.map((product) => { return product._id; }); - this.state.set("productIds", productIds); + const products = Products.find({ _id: { $in: productIds } }).map((product) => { - if (product.__revisions && product.__revisions.length) { - return product.__revisions[0].documentData; - } - return product._id; + return applyProductRevision(product); }); + this.state.set("productIds", productIds); this.state.set("products", products); } }); @@ -46,6 +46,17 @@ Template.productSettings.helpers({ documentIds: productIds }; }, + isVisible() { + const instance = Template.instance(); + const products = instance.state.get("products") || []; + + // Use the first selected product to determin status of bulk, isVisible button + if (Array.isArray(products) && products.length) { + return products[0].isVisible; + } + + return false; + }, hasSelectedProducts() { return this.products.length > 0; }, @@ -138,7 +149,25 @@ Template.productSettingsListItem.inheritsHelpersFrom("productSettingsGridItem"); Template.productSettings.events({ "click [data-event-action=publishProduct]": function () { - ReactionProduct.publishProduct(this.products); + const instance = Template.instance(); + const products = instance.state.get("products") || []; + + if (isRevisionControlEnabled()) { + for (const product of products) { + // Update the visibility using the first selected product to determine the proper + // visibility toggle. This is to ensure that all selected products will become visible or not visible + // at the same time so it's not confusing. + Meteor.call("products/updateProductField", product._id, "isVisible", !products[0].isVisible); + } + } else { + // The legacy behavior will bulk toggle visibilty of each product seperatly. + // + // Example: + // If you selected 10 products, and 5 were visible and 5 were not visible, and then + // clicked the visibility button, 5 products would switched from not visible to visible, and the other 5 + // would be swiched from visible to not visible. + ReactionProduct.publishProduct(products); + } }, "click [data-event-action=cloneProduct]": function () { ReactionProduct.cloneProduct(this.products);