UNPKG

@ampush/centaurus

Version:

Centaurus, is an Ampush repository designed to house common UI components, JS classes, templates and API methods in a central place that can be imported and reused across other Ampush partner repositories as needed.

316 lines (306 loc) 13.2 kB
/*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } const getCookie = (utmKey) => { const cookieString = decodeURIComponent(document.cookie).split('; '); for (let val = 0; val < cookieString.length; val++) { const item = cookieString[val]; const queryVal = item.split(`${utmKey}=`)[1]; const queryKey = item.split('=')[0]; if (utmKey === queryKey) { return queryVal; } } return ''; }; const { hostname } = window.location; const [subDomain, domainName, top] = hostname.split('.'); const host = hostname; const isLocalhost = hostname.indexOf('localhost') !== -1 || hostname.indexOf('0.0.0.0') !== -1; const parsedDomain = isLocalhost ? host : domainName ? `${domainName}.${top || 'com'}` : ''; const setCookie = (cookieStr, doExpires) => { if (doExpires) { const date = new Date(); date.setTime(date.getTime() + 365 * 24 * 60 * 60 * 1000); const expires = `expires=${date.toUTCString()}`; document.cookie = `${cookieStr};${expires};domain=${parsedDomain};path=/`; } else { document.cookie = `${cookieStr};domain=${parsedDomain};path=/`; } }; const Queue = () => { const queue = []; let workingOnPromise = false; const enqueue = (promise) => { return new Promise((resolve, reject) => { queue.push({ promise, resolve, reject, }); }); }; const dequeue = () => { if (workingOnPromise) { return false; } const item = queue.shift(); if (!item) { return false; } try { workingOnPromise = true; item .promise() .then((value) => { workingOnPromise = false; item.resolve(value); dequeue(); }) .catch((err) => { workingOnPromise = false; item.reject(err); dequeue(); }); } catch (err) { workingOnPromise = false; item.reject(err); dequeue(); } return true; }; return { enqueue, dequeue, }; }; /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable compat/compat */ const shopifyClient = require('shopify-buy'); const Queue$1 = Queue(); const CHECKOUT_ID = 'checkoutId'; class ShoppingCart extends EventTarget { /** * @param {string} domain e.g.: 'your-shop-name' * @param {string} token e.g.: 'your-storefront-access-token' * @param {object} extra Additional configuration, such as language and more. */ constructor(config) { super(); /** * Get all products for the instantiated eCommerce * @returns {array} results After promise resolves */ this.getAllProducts = () => __awaiter(this, void 0, void 0, function* () { if (this.isBusy) { return Queue$1.enqueue(this.eCommerce.getAllProducts); } return this.eCommerce.getAllProducts(); }); /** * Get a single product * @param {string} productId the ID of the prodcut to be retrieved * @returns {object} result of the request */ this.getSingleProduct = (productId) => __awaiter(this, void 0, void 0, function* () { if (this.isBusy) { return Queue$1.enqueue(() => this.eCommerce.getSingleProduct(productId)); } const result = yield this.eCommerce.getSingleProduct(productId); return result; }); /** * Add items to the cart * @param {Array} lineItemsToAdd items ids to add * @returns {Object} result of the request */ this.addItems = (lineItemsToAdd) => __awaiter(this, void 0, void 0, function* () { if (this.isBusy) { return Queue$1.enqueue(() => this.eCommerce.addItems(lineItemsToAdd)); } const result = yield this.eCommerce.addItems(lineItemsToAdd); return result; }); /** * Update items in the cart * @param {Array} lineItemsToAdd items ids and quantity to update * @returns {Object} result of the request */ this.updateItems = (lineItemsToUpdate) => __awaiter(this, void 0, void 0, function* () { if (this.isBusy) { return Queue$1.enqueue(() => this.eCommerce.updateItems(lineItemsToUpdate)); } const result = yield this.eCommerce.updateItems(lineItemsToUpdate); return result; }); /** * Remove items from the cart * @param {Array} lineItemsToAdd ids to remove * @returns {Object} result of the request */ this.removeItems = (lineItemsToAdd) => __awaiter(this, void 0, void 0, function* () { if (this.isBusy) { return Queue$1.enqueue(() => this.eCommerce.removeItems(lineItemsToAdd)); } const result = yield this.eCommerce.removeItems(lineItemsToAdd); return result; }); /** * Get cart checkout with items * @param {String} checkoutId id to retrieve * @returns {Object} result of the request */ this.getCart = (checkoutId) => __awaiter(this, void 0, void 0, function* () { if (this.isBusy) { return Queue$1.enqueue(() => this.eCommerce.getCart(checkoutId)); } const result = yield this.eCommerce.getCart(checkoutId); return result; }); const eventReady = (detail) => new CustomEvent('initializeReady', { detail }); this.isBusy = false; this.verbose = false; try { this.verbose = JSON.parse(localStorage.getItem('debug-cart') || 'false'); } catch (error) { console.info('no localstorage'); } const { shopifyConfig } = config || {}; if (shopifyConfig) { const { shopName, token, extra = {} } = shopifyConfig; if (typeof shopName !== 'string' || !shopName) { throw Error(`FAILED! Incorrect shopName: ${shopName}, string type mismatch or empty!`); } if (typeof token !== 'string' || !token) { throw Error(`FAILED! Incorrect token: ${token}, string type mismatch or empty`); } if (extra && typeof extra !== 'object' && Array.isArray(extra)) { throw Error(`FAILED: Incorrect extra: ${extra}, object type mismatch or empty`); } this.isBusy = true; const client = shopifyClient.buildClient(Object.assign({ domain: `${shopName}`, storefrontAccessToken: token }, extra)); this.eCommerce = { checkoutId: '', checkout: {}, getAllProducts: () => client.product.fetchAll(), getSingleProduct: (productId) => client.product.fetch(productId), addItems: (lineItems) => { const mapItems = lineItems.map(({ productId, quantity }) => ({ variantId: productId, quantity, })); const { checkoutId } = this.eCommerce; return client.checkout.addLineItems(checkoutId, mapItems).then((data) => { this.eCommerce.checkout = data; return data; }); }, updateItems: (lineItems) => { const { checkout, checkoutId } = this.eCommerce; const foundItems = []; lineItems.forEach((item) => { checkout.lineItems.find((lineItem) => { if (lineItem.variant.id === item.productId) { foundItems.push({ id: lineItem.id, quantity: lineItem.quantity + (item.quantity || 1) }); } }); }); return client.checkout.updateLineItems(checkoutId, foundItems).then((data) => { this.eCommerce.checkout = data; return data; }); }, removeItems: (lineItems) => { const { checkout, checkoutId } = this.eCommerce; const foundItems = []; lineItems.forEach((item) => { checkout.lineItems.find((lineItem) => { if (lineItem.variant.id === item) { foundItems.push(lineItem.id); } }); }); return client.checkout.removeLineItems(checkoutId, foundItems).then((data) => { this.eCommerce.checkout = data; return data; }); }, getCart: (checkoutId) => { return client.checkout.fetch(checkoutId); }, }; // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this; const handleCreateCheckout = (data) => { const checkoutId = data.id; that.eCommerce.checkoutId = checkoutId; that.eCommerce.checkout = data; that.isBusy = false; Queue$1.dequeue(); setCookie(`${CHECKOUT_ID}=${checkoutId}`); console.info('>> dispatching after create'); this.dispatchEvent(eventReady({ message: 'after create' })); }; try { const checkoutId = getCookie(CHECKOUT_ID); if (checkoutId) { console.info('>> going via cookie'); this.eCommerce .getCart(checkoutId) .then((data) => { if (data) { that.eCommerce.checkout = data; that.eCommerce.checkoutId = checkoutId; that.isBusy = false; Queue$1.dequeue(); console.info('>> dispatching after loading'); this.dispatchEvent(eventReady({ message: 'after loading' })); } else { client.checkout.create().then(handleCreateCheckout); } }) .catch((error) => { console.warn({ error }); }); } else { console.info('>> creating checkout'); client.checkout.create().then(handleCreateCheckout); } } catch (error) { this.verbose && console.info('client.checkout.create: ', { error }); console.error('Something went wrong while creating the cart. Please try with different credentials'); return; } } if (!this.isBusy && !this.eCommerce) { console.info('Click Here:', 'https://github.com/ampush/centaurus/tree/master/src/shopping-cart/readme.md'); throw new Error('No eCommerce set, please send a proper configuration! See above for details.'); } } } export default ShoppingCart;