UNPKG

@nguyenmv2/buy-button

Version:

BuyButton.js allows merchants to build Shopify interfaces into any website

330 lines (271 loc) 9.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _merge = _interopRequireDefault(require("../utils/merge")); var _component = _interopRequireDefault(require("../component")); var _product = _interopRequireDefault(require("./product")); var _template = _interopRequireDefault(require("../template")); var _productSet = _interopRequireDefault(require("../updaters/product-set")); var _productSet2 = _interopRequireDefault(require("../views/product-set")); var _normalizeConfig = _interopRequireDefault(require("../utils/normalize-config")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } function isArray(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; } /** * Renders and fetches data for collection and product set embed. * @extends Component. */ var ProductSet = /*#__PURE__*/ function (_Component) { _inheritsLoose(ProductSet, _Component); /** * create ProductSet * @param {Object} config - configuration object. * @param {Object} props - data and utilities passed down from UI instance. */ function ProductSet(config, props) { var _this; if (Array.isArray(config.id)) { // eslint-disable-next-line no-param-reassign config = (0, _normalizeConfig.default)(config); } else { // eslint-disable-next-line no-param-reassign config = (0, _normalizeConfig.default)(config, 'Collection'); } _this = _Component.call(this, config, props) || this; _this.typeKey = 'productSet'; _this.products = []; _this.cart = null; _this.page = 1; _this.nextModel = { products: [] }; _this.updater = new _productSet.default(_assertThisInitialized(_this)); _this.view = new _productSet2.default(_assertThisInitialized(_this)); return _this; } var _proto = ProductSet.prototype; /** * initializes component by creating model and rendering view. * Creates and initalizes cart if necessary. * Calls renderProducts. * @param {Object} [data] - data to initialize model with. * @return {Promise} promise resolving to instance. */ _proto.init = function init(data) { var _this2 = this; var cartConfig = Object.assign({}, this.globalConfig, { node: this.globalConfig.cartNode, options: this.config }); return this.props.createCart(cartConfig).then(function (cart) { _this2.cart = cart; return _Component.prototype.init.call(_this2, data).then(function (model) { if (model) { return _this2.renderProducts(_this2.model.products); } return _this2; }); }); } /** * fetches products from SDK based on provided config information. * @param {Object} options - query options for request * @return {Promise} promise resolving to collection data. */ ; _proto.sdkFetch = function sdkFetch() { var _this3 = this; var promise; if (this.storefrontId) { if (Array.isArray(this.storefrontId)) { promise = this.props.client.product.fetchMultiple(this.storefrontId); } else { promise = this.props.client.collection.fetchWithProducts(this.storefrontId); } } else if (this.handle) { promise = this.props.client.collection.fetchByHandle(this.handle).then(function (collection) { _this3.storefrontId = collection.id; return _this3.props.client.collection.fetchWithProducts(_this3.storefrontId); }); } return promise.then(function (collectionOrProducts) { var products; if (Array.isArray(collectionOrProducts)) { products = collectionOrProducts; } else { products = collectionOrProducts.products; } return products; }); } /** * call sdkFetch and set model.products to products array. * @throw 'Not Found' if model not returned. * @return {Promise} promise resolving to model data. */ ; _proto.fetchData = function fetchData() { return this.sdkFetch().then(function (products) { if (products.length) { return { products: products }; } throw new Error('Not Found'); }); } /** * make request to SDK for next page. Render button if products on next page exist. * @return {Promise} promise resolving when button is rendered or not. */ ; _proto.showPagination = function showPagination() { var _this4 = this; return this.props.client.fetchNextPage(this.model.products).then(function (data) { _this4.nextModel = { products: data.model }; _this4.view.renderChild(_this4.classes.productSet.paginationButton, _this4.paginationTemplate); _this4.view.resize(); return; }); } /** * append next page worth of products into the DOM */ ; _proto.nextPage = function nextPage() { this.model = this.nextModel; this._userEvent('loadNextPage'); this.renderProducts(); } /** * render product components into productSet container. Show pagination button if necessary. * @return {Promise} promise resolving to instance. */ ; _proto.renderProducts = function renderProducts() { var _this5 = this; if (!this.model.products.length) { return Promise.resolve(); } var productConfig = Object.assign({}, this.globalConfig, { node: this.view.document.querySelector(".".concat(this.classes.productSet.products)), options: (0, _merge.default)({}, this.config, { product: { iframe: false, classes: { wrapper: this.classes.productSet.product } } }) }); if (this.config.productSet.iframe === false) { productConfig.node = this.node.querySelector(".".concat(this.classes.productSet.products)); } var promises = this.model.products.map(function (productModel) { var product = new _product.default(productConfig, _this5.props); _this5.products.push(product); return product.init(productModel); }); return Promise.all(promises).then(function () { _this5.view.resizeUntilFits(); var hasPagination = _this5.model.products[0].hasOwnProperty('hasNextPage'); if (_this5.options.contents.pagination && hasPagination) { _this5.showPagination(); } return _this5; }); }; _createClass(ProductSet, [{ key: "nextButtonClass", get: function get() { return this.nextModel.products.length ? 'is-active' : ''; } /** * get data to be passed to view. * @return {Object} viewData object. */ }, { key: "viewData", get: function get() { return Object.assign({}, this.options.viewData, { classes: this.classes, text: this.options.text, nextButtonClass: this.nextButtonClass }); } /** * get events to be bound to DOM. * @return {Object} */ }, { key: "DOMEvents", get: function get() { return Object.assign({}, _defineProperty({ click: this.props.closeCart.bind(this) }, "click ".concat(this.selectors.productSet.paginationButton), this.nextPage.bind(this)), this.options.DOMEvents); } /** * get template for rendering pagination button. * @return {Object} Template instance */ }, { key: "paginationTemplate", get: function get() { this._paginationTemplate = this._paginationTemplate || new _template.default({ pagination: this.options.templates.pagination }, { pagination: true }, ['pagination']); return this._paginationTemplate; } /** * get info about collection or set to be sent to tracker * @return {Object|Array} */ }, { key: "trackingInfo", get: function get() { var contents = this.config.product.contents; var contentString = Object.keys(contents).filter(function (key) { return contents[key]; }).toString(); var config = { destination: this.config.product.buttonDestination, layout: this.config.product.layout, contents: contentString, checkoutPopup: this.config.cart.popup }; if (isArray(this.id)) { return this.model.products.map(function (product) { var variant = product.variants[0]; return Object.assign({}, config, { id: product.id, name: product.title, variantId: variant.id, variantName: variant.title, price: variant.priceV2.amount, sku: null, isProductSet: true }); }); } return Object.assign(config, { id: this.storefrontId }); } }]); return ProductSet; }(_component.default); exports.default = ProductSet;