UNPKG

@stackend/api

Version:

JS bindings to api.stackend.com

1,224 lines (1,223 loc) 61.5 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (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()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.setIsShopifyApp = exports.setCustomerVatInfo = exports.setCommunityVATS = exports.setVATs = exports.getProductTypeLabel = exports.requestAddressFields = exports.requestCountries = exports.selectShipping = exports.clearCheckout = exports.requestCheckout = exports.checkoutSetEmail = exports.updateShippingAddress = exports.checkoutReplaceItems = exports.setItemQuantity = exports.removeItem = exports.addItem = exports.toLineItemArray = exports.getProductAndVariant2 = exports.getProductAndVariant = exports.checkoutUpdateOrCreateNew = exports.checkoutSetQuantity = exports.checkoutRemove = exports.checkoutAdd = exports.requestOrResetActiveCheckout = exports.createCheckout = exports.createCheckoutFromCart = exports.cartSetQuantity = exports.cartRemove = exports.cartAdd = exports.cartBuyerIdentityUpdate = exports.clearCart = exports.getCart = exports.createCart = exports.hasCheckoutErrors = exports.getProductListing = exports.getProductListingByKey = exports.clearCache = exports.getProductListKey = exports.requestCollections = exports.requestCollection = exports.requestMissingProducts = exports.requestMultipleProducts = exports.requestProduct = exports.requestProductsAndProductTypes = exports.requestProducts = exports.requestProductTypes = exports.getShopDefaults = exports.setShopDefaults = exports.CART_ID_LOCAL_STORAGE_NAME = exports.CHECKOUT_ID_LOCAL_STORAGE_NAME = void 0; exports.setEnableCartNotifications = void 0; var index_1 = require("./index"); var shopReducer_1 = require("./shopReducer"); var api_1 = require("../api"); var throbberActions_1 = require("../throbber/throbberActions"); var util_1 = require("../util"); var graphql_1 = require("../util/graphql"); var vat_1 = require("./vat"); exports.CHECKOUT_ID_LOCAL_STORAGE_NAME = 'checkout'; exports.CART_ID_LOCAL_STORAGE_NAME = 'cart'; /** * Set shop default configuration * @param defaults */ var setShopDefaults = function (defaults) { return function (dispatch) { dispatch({ type: shopReducer_1.SET_SHOP_DEFAULTS, defaults: defaults }); }; }; exports.setShopDefaults = setShopDefaults; /** * Get the shop default configuration */ var getShopDefaults = function () { return function (dispatch, getState) { return getState().shop.defaults; }; }; exports.getShopDefaults = getShopDefaults; /** * Load product types into store * @param req */ var requestProductTypes = function (req) { return function (dispatch, _getState) { return __awaiter(void 0, void 0, void 0, function () { var r; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!req.first) { req.first = 250; /* 250 is max allowed */ } return [4 /*yield*/, dispatch((0, index_1.listProductTypes)(req))]; case 1: r = _a.sent(); if (!!r.error) return [3 /*break*/, 3]; return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_PRODUCT_TYPES, json: r })]; case 2: _a.sent(); _a.label = 3; case 3: return [2 /*return*/, r]; } }); }); }; }; exports.requestProductTypes = requestProductTypes; /** * Request a product listing * @param req */ var requestProducts = function (req) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var r, key; return __generator(this, function (_a) { switch (_a.label) { case 0: (0, index_1.applyDefaults)(req, getState().shop.defaults); return [4 /*yield*/, dispatch((0, index_1.listProducts)(req))]; case 1: r = _a.sent(); if (!!r.error) return [3 /*break*/, 3]; key = dispatch((0, exports.getProductListKey)(req)); return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_LISTING, json: r, request: req, key: key })]; case 2: _a.sent(); _a.label = 3; case 3: return [2 /*return*/, r]; } }); }); }; }; exports.requestProducts = requestProducts; /** * Load products and product types into store * @param req */ var requestProductsAndProductTypes = function (req) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var r, key; return __generator(this, function (_a) { switch (_a.label) { case 0: (0, index_1.applyDefaults)(req, getState().shop.defaults); return [4 /*yield*/, dispatch((0, index_1.listProductsAndTypes)(req))]; case 1: r = _a.sent(); if (!!r.error) return [3 /*break*/, 4]; key = dispatch((0, exports.getProductListKey)(req)); return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_LISTING, json: r, request: req, key: key })]; case 2: _a.sent(); return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_PRODUCT_TYPES, json: r })]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/, r]; } }); }); }; }; exports.requestProductsAndProductTypes = requestProductsAndProductTypes; /** * Load a single product into store * @param req */ var requestProduct = function (req) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var r; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!req.imageMaxWidth) { req.imageMaxWidth = getState().shop.defaults.imageMaxWidth; } return [4 /*yield*/, dispatch((0, index_1.getProduct)(req))]; case 1: r = _a.sent(); if (!!r.error) return [3 /*break*/, 3]; return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_PRODUCT, json: r })]; case 2: _a.sent(); _a.label = 3; case 3: return [2 /*return*/, r]; } }); }); }; }; exports.requestProduct = requestProduct; /** * Request multiple products * @param req */ var requestMultipleProducts = function (req) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var r; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!req.imageMaxWidth) { req.imageMaxWidth = getState().shop.defaults.imageMaxWidth; } return [4 /*yield*/, dispatch((0, index_1.getProducts)(req))]; case 1: r = _a.sent(); if (!!r.error) return [3 /*break*/, 3]; return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_MULTIPLE_PRODUCTS, json: r })]; case 2: _a.sent(); _a.label = 3; case 3: return [2 /*return*/, r]; } }); }); }; }; exports.requestMultipleProducts = requestMultipleProducts; /** * Request missing products * @param req */ var requestMissingProducts = function (req) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var shop, fetchHandles, _i, _a, h, p, r; return __generator(this, function (_b) { switch (_b.label) { case 0: shop = getState().shop; if (!req.imageMaxWidth) { req.imageMaxWidth = shop.defaults.imageMaxWidth; } fetchHandles = []; for (_i = 0, _a = req.handles; _i < _a.length; _i++) { h = _a[_i]; p = shop.products[h]; if (!p) { fetchHandles.push(h); } } if (fetchHandles.length == 0) { return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { products: {} })]; } return [4 /*yield*/, dispatch((0, index_1.getProducts)({ handles: fetchHandles, imageMaxWidth: req.imageMaxWidth }))]; case 1: r = _b.sent(); if (!!r.error) return [3 /*break*/, 3]; return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_MULTIPLE_PRODUCTS, json: r })]; case 2: _b.sent(); _b.label = 3; case 3: return [2 /*return*/, r]; } }); }); }; }; exports.requestMissingProducts = requestMissingProducts; /** * Request a collection, if missing * @param req */ var requestCollection = function (req) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var shop, collection, r; return __generator(this, function (_a) { switch (_a.label) { case 0: shop = getState().shop; collection = shop.collections[req.handle]; if (collection) { return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { collection: collection })]; } if (!req.imageMaxWidth) { req.imageMaxWidth = shop.defaults.listingImageMaxWidth; } return [4 /*yield*/, dispatch((0, index_1.getCollection)(req))]; case 1: r = _a.sent(); if (!r.error) { dispatch({ type: shopReducer_1.RECEIVE_COLLECTION, request: req, json: r }); } return [2 /*return*/, r]; } }); }); }; }; exports.requestCollection = requestCollection; /** * Request a list of all collections, if missing */ var requestCollections = function () { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var shop, r; return __generator(this, function (_a) { switch (_a.label) { case 0: shop = getState().shop; if (shop.allCollections) { return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { collections: shop.allCollections })]; } return [4 /*yield*/, dispatch((0, index_1.getCollections)({}))]; case 1: r = _a.sent(); if (!r.error) { dispatch({ type: shopReducer_1.RECEIVE_COLLECTION_LIST, collections: r.collections }); } return [2 /*return*/, r]; } }); }); }; }; exports.requestCollections = requestCollections; /** * Get the key used to index the product listings in ShopState * @param req */ var getProductListKey = function (req) { return function (dispatch, getState) { var defaults = getState().shop.defaults; (0, index_1.applyDefaults)(req, defaults); // NOTE: This must match the server side implementation function append(s, values) { if (values && values.length !== 0) { var x = []; for (var _i = 0, values_1 = values; _i < values_1.length; _i++) { var v = values_1[_i]; x.push(v.toLowerCase()); } x.sort(function (a, b) { return a.localeCompare(b); }); s += x.join(','); } s += ';'; return s; } var s = ''; s += (req.q || '') + ';'; s = append(s, req.productTypes); s = append(s, req.tags); s += (req.sort || index_1.ProductSortKeys.RELEVANCE) + ';'; s += req.imageMaxWidth + ';'; s += (req.first || '') + ';'; s += (req.after || '') + ';'; s += (req.last || '') + ';'; s += (req.before || '') + ';'; return s; }; }; exports.getProductListKey = getProductListKey; /** * Clear store cache. Does not empty basket or product types */ var clearCache = function () { return function (dispatch) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, dispatch({ type: shopReducer_1.SHOP_CLEAR_CACHE })]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; }; exports.clearCache = clearCache; /** * Get products from a listing * @param key */ var getProductListingByKey = function (key) { return function (dispatch, getState) { if (key === null || typeof key === 'undefined') { return null; } var shop = getState().shop; var listing = shop.productListings[key]; return listing ? listing : null; }; }; exports.getProductListingByKey = getProductListingByKey; /** * Get products from a listing * @param req */ var getProductListing = function (req) { return function (dispatch) { var key = dispatch((0, exports.getProductListKey)(req)); return dispatch((0, exports.getProductListingByKey)(key)); }; }; exports.getProductListing = getProductListing; /** * Check if there are any kind of errors in the checkout * @param result */ function hasCheckoutErrors(result) { return (result && (typeof result.error !== 'undefined' || (result.checkoutUserErrors && result.checkoutUserErrors.length !== 0))); } exports.hasCheckoutErrors = hasCheckoutErrors; /** * Handle product data received via a cart: * Adds the products to the store and transforms the returned data * @param dispatch * @param cart */ function handleCartProductData(dispatch, cart) { if (!cart) { return false; } var products = {}; var lines = { edges: [] }; (0, graphql_1.forEachGraphQLList)(cart.lines, function (i) { var p = i.merchandise.product; // Contains extra product data if (typeof p['availableForSale'] === 'boolean') { var product = p; products[product.handle] = product; // Remove the extra data var li = { node: __assign(__assign({}, i), { merchandise: { id: i.merchandise.id, product: { id: i.merchandise.product.id, handle: i.merchandise.product.handle } } }) }; lines.edges.push(li); } else { lines.edges.push({ node: i }); } }); cart.lines = lines; if (Object.keys(products).length !== 0) { dispatch({ type: shopReducer_1.RECEIVE_MULTIPLE_PRODUCTS, json: (0, api_1.newXcapJsonResult)('success', { products: products }) }); } dispatch({ type: shopReducer_1.RECEIVE_CART, cart: cart }); return true; } /** * Create a cart */ function createCart(req) { var _this = this; return function (dispatch, getState) { return __awaiter(_this, void 0, void 0, function () { var ci, communities, countryCode, r; var _a, _b, _c, _d; return __generator(this, function (_e) { switch (_e.label) { case 0: _e.trys.push([0, , 3, 5]); return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(true))]; case 1: _e.sent(); // FIXME: Improve country detection if (!req.buyerIdentity) { req.buyerIdentity = {}; } if (!req.buyerIdentity.countryCode) { ci = dispatch((0, vat_1.getCustomerInfo)()); if (ci && ci.customerCountryCode) { req.buyerIdentity.countryCode = ci.customerCountryCode; } else { communities = getState().communities; countryCode = (_c = (_b = (_a = communities.community) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.shop) === null || _c === void 0 ? void 0 : _c.countryCode; if (countryCode) { req.buyerIdentity.countryCode = countryCode; } } } return [4 /*yield*/, dispatch((0, index_1.createCart)(req))]; case 2: r = _e.sent(); if (r.error || ((_d = r.userErrors) === null || _d === void 0 ? void 0 : _d.length) !== 0) { return [2 /*return*/, r]; } if (r.cart) { dispatch((0, util_1.setLocalStorageItem)(exports.CART_ID_LOCAL_STORAGE_NAME, r.cart.id)); } handleCartProductData(dispatch, r.cart); return [2 /*return*/, r]; case 3: return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(false))]; case 4: _e.sent(); return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; } exports.createCart = createCart; /** * If the user has established a cart, get it * @param imageMaxWidth * @param forceRefresh */ function getCart(_a) { var _this = this; var imageMaxWidth = _a.imageMaxWidth, forceRefresh = _a.forceRefresh; return function (dispatch, getState) { return __awaiter(_this, void 0, void 0, function () { var shop, useCache, cartId, r; return __generator(this, function (_a) { switch (_a.label) { case 0: shop = getState().shop; useCache = typeof forceRefresh === 'undefined' || !forceRefresh; if (useCache && shop.cart) { return [2 /*return*/, shop.cart]; } cartId = dispatch((0, util_1.getLocalStorageItem)(exports.CART_ID_LOCAL_STORAGE_NAME)); if (!cartId) { return [2 /*return*/, null]; } return [4 /*yield*/, dispatch((0, index_1.getCart)({ cartId: cartId, imageMaxWidth: imageMaxWidth }))]; case 1: r = _a.sent(); if (r.cart) { handleCartProductData(dispatch, r.cart); return [2 /*return*/, r.cart]; } return [4 /*yield*/, dispatch(clearCart())]; case 2: _a.sent(); return [2 /*return*/, null]; } }); }); }; } exports.getCart = getCart; /** * Clear cart data and remove the id */ function clearCart() { var _this = this; return function (dispatch) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: dispatch((0, util_1.removeLocalStorageItem)(exports.CART_ID_LOCAL_STORAGE_NAME)); return [4 /*yield*/, dispatch({ type: shopReducer_1.CLEAR_CART })]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; } exports.clearCart = clearCart; /** * Alter buyer information */ function cartBuyerIdentityUpdate(buyerIdentity) { var _this = this; return function (dispatch) { return __awaiter(_this, void 0, void 0, function () { var cart, r; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, , 4, 6]); return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(true))]; case 1: _a.sent(); return [4 /*yield*/, dispatch(getCart({}))]; case 2: cart = _a.sent(); if (!cart) { // FIXME: Create empty cart here? return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { cart: null })]; } return [4 /*yield*/, dispatch((0, index_1.cartBuyerIdentityUpdate)({ cartId: cart.id, buyerIdentity: buyerIdentity }))]; case 3: r = _a.sent(); if (r.cart) { handleCartProductData(dispatch, r.cart); } return [2 /*return*/, r]; case 4: return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(false))]; case 5: _a.sent(); return [7 /*endfinally*/]; case 6: return [2 /*return*/]; } }); }); }; } exports.cartBuyerIdentityUpdate = cartBuyerIdentityUpdate; /** * Add an item to the cart or increment the quantity. Creating a new cart if needed. * @param product * @param variant * @param quantity */ function cartAdd(product, variant, quantity) { var _this = this; return function (dispatch) { return __awaiter(_this, void 0, void 0, function () { var q, lines, r, cart, line; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!product || !variant) { throw new Error('product and variant required'); } q = quantity || 1; lines = [{ merchandiseId: variant.id, quantity: q }]; r = null; _a.label = 1; case 1: _a.trys.push([1, , 11, 13]); return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(true))]; case 2: _a.sent(); return [4 /*yield*/, dispatch(getCart({}))]; case 3: cart = _a.sent(); if (!cart) return [3 /*break*/, 8]; line = (0, index_1.cartFindLine)(cart, variant.id); if (!line) return [3 /*break*/, 5]; return [4 /*yield*/, dispatch(cartSetQuantity(variant.id, line.quantity + q))]; case 4: r = _a.sent(); return [3 /*break*/, 7]; case 5: return [4 /*yield*/, dispatch((0, index_1.cartLinesAdd)({ cartId: cart.id, lines: lines }))]; case 6: r = _a.sent(); if (!r.error) { handleCartProductData(dispatch, r.cart); } _a.label = 7; case 7: return [3 /*break*/, 10]; case 8: return [4 /*yield*/, dispatch(createCart({ lines: lines }))]; case 9: r = _a.sent(); _a.label = 10; case 10: if (!r.error) { dispatch({ type: shopReducer_1.ADD_TO_BASKET, product: product, variant: variant, variantId: variant.id, quantity: q }); } return [2 /*return*/, r]; case 11: return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(false))]; case 12: _a.sent(); return [7 /*endfinally*/]; case 13: return [2 /*return*/]; } }); }); }; } exports.cartAdd = cartAdd; /** * For a product in the cart, decrement the quantity. Remove if 0. * NOTE: This differs from the Shopify behavior that removes the line completely. * @param product * @param variant * @param quantity */ function cartRemove(product, variant, quantity) { var _this = this; return function (dispatch, _getState) { return __awaiter(_this, void 0, void 0, function () { var cart, line, r, q, newQuantity; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!product || !variant) { throw new Error('product and variant required'); } return [4 /*yield*/, dispatch(getCart({}))]; case 1: cart = _a.sent(); if (!cart) { // The cart has probably expired. Improve this situation? return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { cart: null })]; } line = (0, index_1.cartFindLine)(cart, variant.id); if (line == null) { console.warn('No such product variant in cart', variant.id, cart.lines.edges); return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { cart: null })]; } _a.label = 2; case 2: _a.trys.push([2, , 8, 10]); return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(true))]; case 3: _a.sent(); r = null; q = quantity || 1; newQuantity = line.quantity - q; if (!(newQuantity <= 0)) return [3 /*break*/, 5]; return [4 /*yield*/, dispatch((0, index_1.cartLinesRemove)({ cartId: cart.id, lineIds: [line.id] }))]; case 4: r = _a.sent(); return [3 /*break*/, 7]; case 5: return [4 /*yield*/, dispatch((0, index_1.cartLinesUpdate)({ cartId: cart.id, lines: [ { id: line.id, merchandiseId: line.merchandise.id, quantity: newQuantity } ] }))]; case 6: r = _a.sent(); _a.label = 7; case 7: if (!r.error) { handleCartProductData(dispatch, r.cart); dispatch({ type: shopReducer_1.REMOVE_FROM_BASKET, product: product, variant: variant, variantId: variant.id, quantity: q }); } return [2 /*return*/, r]; case 8: return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(false))]; case 9: _a.sent(); return [7 /*endfinally*/]; case 10: return [2 /*return*/]; } }); }); }; } exports.cartRemove = cartRemove; /** * Set quantity of an item. * @param variantId * @param quantity */ function cartSetQuantity(variantId, quantity) { var _this = this; return function (dispatch) { return __awaiter(_this, void 0, void 0, function () { var cart, line, r; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, dispatch(getCart({}))]; case 1: cart = _a.sent(); if (!!cart) return [3 /*break*/, 3]; if (quantity < 1) { return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { cart: null })]; } return [4 /*yield*/, dispatch(createCart({ lines: [{ merchandiseId: variantId, quantity: quantity || 1 }] }))]; case 2: return [2 /*return*/, _a.sent()]; case 3: line = (0, index_1.cartFindLine)(cart, variantId); if (!line) { console.warn('No such product variant in cart', variantId, cart.lines.edges); return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { cart: null })]; } _a.label = 4; case 4: _a.trys.push([4, , 10, 12]); return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(true))]; case 5: _a.sent(); r = null; if (!(quantity < 1)) return [3 /*break*/, 7]; return [4 /*yield*/, dispatch((0, index_1.cartLinesRemove)({ cartId: cart.id, lineIds: [line.id] }))]; case 6: r = _a.sent(); return [3 /*break*/, 9]; case 7: return [4 /*yield*/, dispatch((0, index_1.cartLinesUpdate)({ cartId: cart.id, lines: [{ id: line.id, quantity: quantity, merchandiseId: variantId }] }))]; case 8: r = _a.sent(); _a.label = 9; case 9: if (!r.error) { handleCartProductData(dispatch, r.cart); } return [2 /*return*/, r]; case 10: return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(false))]; case 11: _a.sent(); return [7 /*endfinally*/]; case 12: return [2 /*return*/]; } }); }); }; } exports.cartSetQuantity = cartSetQuantity; /** * Create a checkout from the cart, possibly reusing */ function createCheckoutFromCart() { var _this = this; return function (dispatch, getState) { return __awaiter(_this, void 0, void 0, function () { var cart, shop, lineItems; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, , 4, 5]); dispatch((0, throbberActions_1.setModalThrobberVisible)(true)); return [4 /*yield*/, dispatch(getCart({}))]; case 1: cart = _a.sent(); if (!cart) { return [2 /*return*/, (0, api_1.newXcapJsonErrorResult)('cart_not_available')]; } // Reuse existing checkout, if available. The customer may have entered address data return [4 /*yield*/, dispatch((0, exports.requestOrResetActiveCheckout)({}))]; case 2: // Reuse existing checkout, if available. The customer may have entered address data _a.sent(); shop = getState().shop; lineItems = (0, index_1.cartToLineItems)(cart); return [4 /*yield*/, dispatch((0, exports.checkoutUpdateOrCreateNew)(shop, lineItems))]; case 3: return [2 /*return*/, _a.sent()]; case 4: dispatch((0, throbberActions_1.setModalThrobberVisible)(false)); return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; } exports.createCheckoutFromCart = createCheckoutFromCart; /** * Create a checkout */ function createCheckout(req) { var _this = this; return function (dispatch) { return __awaiter(_this, void 0, void 0, function () { var r; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, , 5, 7]); return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(true))]; case 1: _a.sent(); return [4 /*yield*/, dispatch((0, index_1.createCheckout)(req))]; case 2: r = _a.sent(); if (!!hasCheckoutErrors(r)) return [3 /*break*/, 4]; if (r.response.checkout) { dispatch((0, util_1.setLocalStorageItem)(exports.CHECKOUT_ID_LOCAL_STORAGE_NAME, r.response.checkout.id)); } handleCheckoutProductData(dispatch, r.checkout); return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_CHECKOUT, checkoutUserErrors: r.response.checkoutUserErrors, checkout: r.response.checkout })]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/, r]; case 5: return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(false))]; case 6: _a.sent(); return [7 /*endfinally*/]; case 7: return [2 /*return*/]; } }); }); }; } exports.createCheckout = createCheckout; /** * If the user has an active checkout set in the local storage, request that checkout to be loaded. * If the checkout is turned into an order, the checkout is reset in local storage. * @param imageMaxWidth */ var requestOrResetActiveCheckout = function (_a) { var imageMaxWidth = _a.imageMaxWidth; return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var checkoutId, r; return __generator(this, function (_a) { switch (_a.label) { case 0: checkoutId = dispatch((0, util_1.getLocalStorageItem)(exports.CHECKOUT_ID_LOCAL_STORAGE_NAME)); if (!checkoutId) { return [2 /*return*/, (0, api_1.newXcapJsonResult)('success', { checkout: null })]; } if (!imageMaxWidth) { imageMaxWidth = getState().shop.defaults.imageMaxWidth; } return [4 /*yield*/, dispatch((0, index_1.getCheckout)({ checkoutId: checkoutId, imageMaxWidth: imageMaxWidth }))]; case 1: r = _a.sent(); if (!(!r.error && r.checkout)) return [3 /*break*/, 4]; if (!r.checkout.completedAt) return [3 /*break*/, 2]; // Checkout is turned into an order. Remove dispatch((0, exports.clearCheckout)()); return [3 /*break*/, 4]; case 2: handleCheckoutProductData(dispatch, r.checkout); return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_CHECKOUT, checkoutUserErrors: null, checkout: r.checkout })]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/, r]; } }); }); }; }; exports.requestOrResetActiveCheckout = requestOrResetActiveCheckout; /** * Handle product data received via checkout: * Adds the products to the store and tranforms the returned data * @param dispatch * @param checkout */ function handleCheckoutProductData(dispatch, checkout) { if (!checkout) { return false; } var products = {}; var lineItems = { edges: [] }; (0, graphql_1.forEachGraphQLList)(checkout.lineItems, function (i) { var p = i.variant.product; // Contains extra product data if (typeof p['availableForSale'] === 'boolean') { var product = p; products[product.handle] = product; // Remove the extra data var li = { node: { id: i.id, quantity: i.quantity, title: i.title, variant: { id: i.variant.id, product: { id: i.variant.product.id, handle: i.variant.product.handle } } } }; lineItems.edges.push(li); } else { lineItems.edges.push({ node: i }); } }); checkout.lineItems = lineItems; if (Object.keys(products).length === 0) { return false; } dispatch({ type: shopReducer_1.RECEIVE_MULTIPLE_PRODUCTS, json: (0, api_1.newXcapJsonResult)('success', { products: products }) }); return true; } /** * Add an item to the checkout. Possibly creating a new checkout. * @param product * @param variant * @param quantity */ var checkoutAdd = function (product, variant, quantity) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var q, shop, lineItems, r; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!product || !variant) { throw new Error('product and variant required'); } q = quantity || 1; shop = getState().shop; lineItems = addItem(toLineItemArray(shop.checkout), variant.id, q); return [4 /*yield*/, dispatch((0, exports.checkoutUpdateOrCreateNew)(shop, lineItems, product.handle, variant.id, quantity || 1))]; case 1: r = _a.sent(); if (!r.error) { dispatch({ type: shopReducer_1.ADD_TO_BASKET, product: product, variant: variant, variantId: variant.id, quantity: q }); } return [2 /*return*/, r]; } }); }); }; }; exports.checkoutAdd = checkoutAdd; /** * Remove a item from the checkout, possibly creating a new checkout * @param product * @param variant * @param quantity */ var checkoutRemove = function (product, variant, quantity) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var shop, q, lineItems, r; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!product || !variant) { throw new Error('product and variant required'); } shop = getState().shop; q = quantity || 1; lineItems = removeItem(toLineItemArray(shop.checkout), variant.id, q); return [4 /*yield*/, dispatch((0, exports.checkoutUpdateOrCreateNew)(shop, lineItems))]; case 1: r = _a.sent(); if (!r.error) { dispatch({ type: shopReducer_1.REMOVE_FROM_BASKET, product: product, variant: variant, variantId: variant.id, quantity: q }); } return [2 /*return*/, r]; } }); }); }; }; exports.checkoutRemove = checkoutRemove; /** * Set quantity of an item. * @param variantId * @param quantity */ var checkoutSetQuantity = function (variantId, quantity) { return function (dispatch, getState) { return __awaiter(void 0, void 0, void 0, function () { var shop, lineItems; return __generator(this, function (_a) { shop = getState().shop; lineItems = setItemQuantity(toLineItemArray(shop.checkout), variantId, quantity); return [2 /*return*/, dispatch((0, exports.checkoutUpdateOrCreateNew)(shop, lineItems))]; }); }); }; }; exports.checkoutSetQuantity = checkoutSetQuantity; /** * Update the items in the checkout. Create a new checkout if needed. * @param shop * @param lineItems * @param addedProductHandle * @param variantId * @param quantity */ var checkoutUpdateOrCreateNew = function (shop, lineItems, addedProductHandle, variantId, quantity) { return function (dispatch) { return __awaiter(void 0, void 0, void 0, function () { var r; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!(shop.checkout === null || shop.checkout.completedAt !== null)) return [3 /*break*/, 2]; return [4 /*yield*/, dispatch(createCheckout({ input: { lineItems: lineItems }, addedProductHandle: addedProductHandle, variantId: variantId, quantity: quantity }))]; case 1: r = _a.sent(); return [3 /*break*/, 4]; case 2: return [4 /*yield*/, dispatch((0, exports.checkoutReplaceItems)({ checkoutId: shop.checkout.id, lineItems: lineItems, addedProductHandle: addedProductHandle, variantId: variantId, quantity: quantity }))]; case 3: r = _a.sent(); _a.label = 4; case 4: if (!r.error) { dispatch({ type: shopReducer_1.BASKET_UPDATED }); } return [2 /*return*/, r]; } }); }); }; }; exports.checkoutUpdateOrCreateNew = checkoutUpdateOrCreateNew; /** * Given a CheckoutLineItem, find the corresponding product variant * @param shop * @param item */ function getProductAndVariant(shop, item) { return getProductAndVariant2(shop, item.variant.product.handle, item.variant.id); } exports.getProductAndVariant = getProductAndVariant; /** * Given a product handle and variantId, find the corresponding product variant * @param shop * @param productHandle * @param variantId */ function getProductAndVariant2(shop, productHandle, variantId) { var products = shop.products; var product = products[productHandle]; if (!product) { return null; } var n = product.variants.edges.find(function (n) { return n.node.id === variantId; }); if (!n) { return null; } return { product: product, variant: n.node }; } exports.getProductAndVariant2 = getProductAndVariant2; /** * Convert the line items of the checkout to an array suitable * for calling the various functions * @param checkout */ function toLineItemArray(checkout) { if (!checkout || !checkout.lineItems) { return []; } return (0, graphql_1.mapGraphQLList)(checkout.lineItems, function (i) { return { variantId: i.variant.id, quantity: i.quantity }; }); } exports.toLineItemArray = toLineItemArray; /** * Add line items * @param items * @param variantId * @param quantity */ function addItem(items, variantId, quantity) { var item = items.find(function (i) { return i.variantId == variantId; }); if (item) { item.quantity += quantity || 1; } else { items.push({ variantId: variantId, quantity: quantity || 1 }); } return items.filter(function (i) { return i.quantity > 0; }); } exports.addItem = addItem; /** * Remove line items * @param items * @param variantId * @param quantity */ function removeItem(items, variantId, quantity) { var item = items.find(function (i) { return i.variantId == variantId; }); if (item) { item.quantity -= quantity || 1; } return items.filter(function (i) { return i.quantity > 0; }); } exports.removeItem = removeItem; /** * Set item quantity * @param items * @param variantId * @param quantity */ function setItemQuantity(items, variantId, quantity) { var item = items.find(function (i) { return i.variantId == variantId; }); if (item) { item.quantity = quantity; } else { items.push({ variantId: variantId, quantity: quantity }); } return items.filter(function (i) { return i.quantity > 0; }); } exports.setItemQuantity = setItemQuantity; /** * Replace the items in the checkout * @param req */ var checkoutReplaceItems = function (req) { return function (dispatch) { return __awaiter(void 0, void 0, void 0, function () { var r; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, , 5, 7]); return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(true))]; case 1: _a.sent(); return [4 /*yield*/, dispatch((0, index_1.checkoutReplaceItems)(req))]; case 2: r = _a.sent(); if (!!hasCheckoutErrors(r)) return [3 /*break*/, 4]; return [4 /*yield*/, dispatch({ type: shopReducer_1.RECEIVE_CHECKOUT, checkoutUserErrors: r.response.checkoutUserErrors, checkout: r.response.checkout })]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/, r]; case 5: return [4 /*yield*/, dispatch((0, throbberActions_1.setModalThrobberVisible)(false))];