Instantly share code, notes, and snippets.
Created
April 17, 2020 18:48
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save marioloncarek/3e08411132377c7a4b02267c39905929 to your computer and use it in GitHub Desktop.
for James with tags wrapped
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {formatMoney} from '@shopify/theme-currency/currency'; | |
| import 'whatwg-fetch'; | |
| import serialize from 'form-serialize'; | |
| class GoCart { | |
| constructor(options) { | |
| const defaults = { | |
| cartModalFail: '.js-go-cart-modal-fail', | |
| cartModalFailClose: '.js-go-cart-modal-fail-close', | |
| cartModal: '.js-go-cart-modal', | |
| cartModalClose: '.js-go-cart-modal-close', | |
| cartModalContent: '.js-go-cart-modal-content', | |
| cartDrawer: '.js-go-cart-drawer', | |
| cartDrawerContent: '.js-go-cart-drawer-content', | |
| cartDrawerSubTotal: '.js-go-cart-drawer-subtotal', | |
| cartDrawerFooter: '.js-go-cart-drawer-footer', | |
| cartDrawerClose: '.js-go-cart-drawer-close', | |
| cartMiniCart: '.js-go-cart-mini-cart', | |
| cartMiniCartContent: '.js-go-cart-mini-cart-content', | |
| cartMiniCartSubTotal: '.js-go-cart-mini-cart-subtotal', | |
| cartMiniCartFooter: '.js-go-cart-mini-cart-footer', | |
| cartTrigger: '.js-go-cart-trigger', | |
| cartOverlay: '.js-go-cart-overlay', | |
| cartCount: '.js-go-cart-counter', | |
| addToCart: '.js-go-cart-add-to-cart', | |
| removeFromCart: '.js-go-cart-remove-from-cart', | |
| removeFromCartNoDot: 'js-go-cart-remove-from-cart', | |
| itemQuantity: '.js-go-cart-quantity', | |
| itemQuantityPlus: '.js-go-cart-quantity-plus', | |
| itemQuantityMinus: '.js-go-cart-quantity-minus', | |
| cartMode: 'drawer', | |
| drawerDirection: 'right', | |
| displayModal: false, | |
| }; | |
| this.defaults = Object.assign({}, defaults, options); | |
| this.cartModalFail = document.querySelector(this.defaults.cartModalFail); | |
| this.cartModalFailClose = document.querySelector(this.defaults.cartModalFailClose); | |
| this.cartModal = document.querySelector(this.defaults.cartModal); | |
| this.cartModalClose = document.querySelectorAll(this.defaults.cartModalClose); | |
| this.cartModalContent = document.querySelector(this.defaults.cartModalContent); | |
| this.cartDrawer = document.querySelector(this.defaults.cartDrawer); | |
| this.cartDrawerContent = document.querySelector(this.defaults.cartDrawerContent); | |
| this.cartDrawerSubTotal = document.querySelector(this.defaults.cartDrawerSubTotal); | |
| this.cartDrawerFooter = document.querySelector(this.defaults.cartDrawerFooter); | |
| this.cartDrawerClose = document.querySelector(this.defaults.cartDrawerClose); | |
| this.cartMiniCart = document.querySelector(this.defaults.cartMiniCart); | |
| this.cartMiniCartContent = document.querySelector(this.defaults.cartMiniCartContent); | |
| this.cartMiniCartSubTotal = document.querySelector(this.defaults.cartMiniCartSubTotal); | |
| this.cartMiniCartFooter = document.querySelector(this.defaults.cartMiniCartFooter); | |
| this.cartTrigger = document.querySelector(this.defaults.cartTrigger); | |
| this.cartOverlay = document.querySelector(this.defaults.cartOverlay); | |
| this.cartCount = document.querySelector(this.defaults.cartCount); | |
| this.addToCart = document.querySelectorAll(this.defaults.addToCart); | |
| this.removeFromCart = this.defaults.removeFromCart; | |
| this.removeFromCartNoDot = this.defaults.removeFromCartNoDot; | |
| this.itemQuantity = this.defaults.itemQuantity; | |
| this.itemQuantityPlus = this.defaults.itemQuantityPlus; | |
| this.itemQuantityMinus = this.defaults.itemQuantityMinus; | |
| this.cartMode = this.defaults.cartMode; | |
| this.drawerDirection = this.defaults.drawerDirection; | |
| this.displayModal = this.defaults.displayModal; | |
| this.init(); | |
| } | |
| get isDrawerMode() { | |
| return this.cartMode === 'drawer'; | |
| } | |
| init() { | |
| this.fetchCart(); | |
| if (this.isDrawerMode) { | |
| this.setDrawerDirection(); | |
| } | |
| this.addToCart.forEach((item) => { | |
| item.addEventListener('click', (event) => { | |
| event.preventDefault(); | |
| const formID = item.parentNode.getAttribute('id'); | |
| this.addItemToCart(formID); | |
| }); | |
| }); | |
| this.cartTrigger.addEventListener('click', () => { | |
| if (this.isDrawerMode) { | |
| this.openCartDrawer(); | |
| } else { | |
| this.openMiniCart(); | |
| } | |
| this.openCartOverlay(); | |
| }); | |
| this.cartOverlay.addEventListener('click', () => { | |
| this.closeFailModal(); | |
| this.closeCartModal(); | |
| if (this.isDrawerMode) { | |
| this.closeCartDrawer(); | |
| } else { | |
| this.closeMiniCart(); | |
| } | |
| this.closeCartOverlay(); | |
| }); | |
| if (this.isDrawerMode) { | |
| this.cartDrawerClose.addEventListener('click', () => { | |
| this.closeCartDrawer(); | |
| this.closeCartOverlay(); | |
| }); | |
| } | |
| if (this.displayModal) { | |
| this.cartModalClose.forEach((item) => { | |
| item.addEventListener('click', () => { | |
| this.closeFailModal(); | |
| this.closeCartModal(); | |
| if (this.isDrawerMode) { | |
| this.closeCartDrawer(); | |
| } else { | |
| this.closeMiniCart(); | |
| } | |
| this.closeCartOverlay(); | |
| }); | |
| }); | |
| } | |
| this.cartModalFailClose.addEventListener('click', () => { | |
| this.closeFailModal(); | |
| this.closeCartModal(); | |
| if (this.isDrawerMode) { | |
| this.closeCartDrawer(); | |
| } else { | |
| this.closeMiniCart(); | |
| } | |
| this.closeCartOverlay(); | |
| }); | |
| } | |
| fetchCart(callback) { | |
| window.fetch('/cart.js', { | |
| credentials: 'same-origin', | |
| method: 'GET', | |
| }) | |
| .then((response) => response.json()) | |
| .then((cart) => this.fetchHandler(cart, callback)) | |
| .catch((error) => { | |
| this.ajaxRequestFail(); | |
| throw new Error(error); | |
| }); | |
| } | |
| addItemToCart(formID) { | |
| const form = document.querySelector(`#${formID}`); | |
| const formData = serialize(form, {hash: true}); | |
| window.fetch('/cart/add.js', { | |
| method: 'POST', | |
| credentials: 'include', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(formData), | |
| }) | |
| .then((response) => response.json()) | |
| .then((product) => this.addItemToCartHandler(product)) | |
| .catch((error) => { | |
| this.ajaxRequestFail(); | |
| throw new Error(error); | |
| }); | |
| } | |
| removeItem(line) { | |
| const quantity = 0; | |
| window.fetch('/cart/change.js', { | |
| method: 'POST', | |
| credentials: 'same-origin', | |
| body: JSON.stringify({quantity, line}), | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| }) | |
| .then((response) => response.json()) | |
| .then(() => this.fetchCart()) | |
| .catch((error) => { | |
| this.ajaxRequestFail(); | |
| throw new Error(error); | |
| }); | |
| } | |
| changeItemQuantity(line, quantity) { | |
| window.fetch('/cart/change.js', { | |
| method: 'POST', | |
| credentials: 'same-origin', | |
| body: JSON.stringify({quantity, line}), | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| }) | |
| .then((response) => response.json()) | |
| .then(() => this.fetchCart()) | |
| .catch((error) => { | |
| this.ajaxRequestFail(); | |
| throw new Error(error); | |
| }); | |
| } | |
| cartItemCount(cart) { | |
| this.cartCount.innerHTML = cart.item_count; | |
| } | |
| fetchAndOpenCart() { | |
| this.fetchCart(() => { | |
| if (this.isDrawerMode) { | |
| this.openCartDrawer(); | |
| } else { | |
| this.openMiniCart(); | |
| } | |
| this.openCartOverlay(); | |
| }); | |
| } | |
| fetchAndOpenModal(product) { | |
| this.fetchCart(() => { | |
| this.renderCartModal(product); | |
| this.openCartModal(); | |
| this.openCartOverlay(); | |
| }); | |
| } | |
| fetchHandler(cart, callback) { | |
| this.cartItemCount(cart); | |
| if (this.isDrawerMode) { | |
| if (cart.item_count === 0) { | |
| this.renderBlankCartDrawer(); | |
| this.cartDrawerFooter.classList.add('is-invisible'); | |
| } else { | |
| this.renderDrawerCart(cart); | |
| this.cartDrawerFooter.classList.remove('is-invisible'); | |
| if ((typeof callback) === 'function') { | |
| callback(cart); | |
| } | |
| } | |
| } else if (cart.item_count === 0) { | |
| this.renderBlankMiniCart(); | |
| this.cartMiniCartFooter.classList.add('is-invisible'); | |
| } else { | |
| this.renderMiniCart(cart); | |
| this.cartMiniCartFooter.classList.remove('is-invisible'); | |
| if ((typeof callback) === 'function') { | |
| callback(cart); | |
| } | |
| } | |
| } | |
| addItemToCartHandler(product) { | |
| return this.displayModal ? this.fetchAndOpenModal(product) : this.fetchAndOpenCart(); | |
| } | |
| ajaxRequestFail() { | |
| this.openFailModal(); | |
| this.openCartOverlay(); | |
| } | |
| renderCartModal(product) { | |
| this.clearCartModal(); | |
| let productVariant = product.variant_title; | |
| if (productVariant === null) { | |
| productVariant = ''; | |
| } else { | |
| productVariant = `(${productVariant})`; | |
| } | |
| const cartSingleProduct = ` | |
| <div class="go-cart-modal-item"> | |
| <div class="go-cart-item__image" style="background-image: url(${product.image});"></div> | |
| <div class="go-cart-item__info"> | |
| <a href="${product.url}" class="go-cart-item__title">${product.product_title} ${productVariant}</a> was added to your cart. | |
| </div> | |
| </div> | |
| `; | |
| this.cartModalContent.innerHTML += cartSingleProduct; | |
| } | |
| renderDrawerCart(cart) { | |
| this.clearCartDrawer(); | |
| cart.items.forEach((item, index) => { | |
| window.fetch(`/products/${item.handle}.js`, { | |
| credentials: 'same-origin', | |
| method: 'GET', | |
| }) | |
| .then((response) => response.json()) | |
| .then((product) => { | |
| const singleLine = document.querySelector(`[data-line="${Number(index + 1)}"]`); | |
| const tagWrapper = singleLine.querySelector('.go-cart-item__tag'); | |
| product.tags.forEach((item) => { | |
| const itemClass = item.toLowerCase() | |
| .replace(/ /g, '-'); | |
| tagWrapper.innerHTML += `<span class="go-cart-item__tag--${itemClass}">${item}</span>`; | |
| }); | |
| }) | |
| .catch((error) => { | |
| throw new Error(error); | |
| }); | |
| let itemVariant = item.variant_title; | |
| if (itemVariant === null) { | |
| itemVariant = ''; | |
| } | |
| const cartSingleProduct = ` | |
| <div class="go-cart-item__single" data-line="${Number(index + 1)}"> | |
| <div class="go-cart-item__info-wrapper"> | |
| <div class="go-cart-item__image" style="background-image: url(${item.image});"></div> | |
| <div class="go-cart-item__info"> | |
| <a href="${item.url}" class="go-cart-item__title">${item.product_title}</a> | |
| <div class="go-cart-item__variant">${itemVariant}</div> | |
| <div class="go-cart-item__tag"></div> | |
| <div class="go-cart-item__quantity"> | |
| <span class="go-cart-item__quantity-label">Quantity: </span> | |
| <span class="go-cart-item__quantity-button js-go-cart-quantity-minus">-</span> | |
| <input class="go-cart-item__quantity-number js-go-cart-quantity" type="number" value="${item.quantity}" disabled> | |
| <span class="go-cart-item__quantity-button js-go-cart-quantity-plus">+</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="go-cart-item__price">${formatMoney(item.line_price)}</div> | |
| <a class="go-cart-item__remove ${this.removeFromCartNoDot}">Remove</a> | |
| </div> | |
| `; | |
| this.cartDrawerContent.innerHTML += cartSingleProduct; | |
| }); | |
| this.cartDrawerSubTotal.innerHTML = formatMoney(cart.total_price); | |
| this.cartDrawerSubTotal.parentNode.classList.remove('is-invisible'); | |
| const removeFromCart = document.querySelectorAll(this.removeFromCart); | |
| removeFromCart.forEach((item) => { | |
| item.addEventListener('click', () => { | |
| GoCart.removeItemAnimation(item.parentNode); | |
| const line = item.parentNode.getAttribute('data-line'); | |
| this.removeItem(line); | |
| }); | |
| }); | |
| const itemQuantityPlus = document.querySelectorAll(this.itemQuantityPlus); | |
| itemQuantityPlus.forEach((item) => { | |
| item.addEventListener('click', () => { | |
| const line = item.parentNode.parentNode.parentNode.parentNode.getAttribute('data-line'); | |
| const quantity = Number(item.parentNode.querySelector(this.itemQuantity).value) + 1; | |
| this.changeItemQuantity(line, quantity); | |
| }); | |
| }); | |
| const itemQuantityMinus = document.querySelectorAll(this.itemQuantityMinus); | |
| itemQuantityMinus.forEach((item) => { | |
| item.addEventListener('click', () => { | |
| const line = item.parentNode.parentNode.parentNode.parentNode.getAttribute('data-line'); | |
| const quantity = Number(item.parentNode.querySelector(this.itemQuantity).value) - 1; | |
| this.changeItemQuantity(line, quantity); | |
| if (Number((item.parentNode.querySelector(this.itemQuantity).value - 1)) === 0) { | |
| GoCart.removeItemAnimation(item.parentNode.parentNode.parentNode.parentNode); | |
| } | |
| }); | |
| }); | |
| } | |
| renderMiniCart(cart) { | |
| this.clearMiniCart(); | |
| cart.items.forEach((item, index) => { | |
| let itemVariant = item.variant_title; | |
| if (itemVariant === null) { | |
| itemVariant = ''; | |
| } | |
| const cartSingleProduct = ` | |
| <div class="go-cart-item__single" data-line="${Number(index + 1)}"> | |
| <div class="go-cart-item__info-wrapper"> | |
| <div class="go-cart-item__image" style="background-image: url(${item.image});"></div> | |
| <div class="go-cart-item__info"> | |
| <a href="${item.url}" class="go-cart-item__title">${item.product_title}</a> | |
| <div class="go-cart-item__variant">${itemVariant}</div> | |
| <div class="go-cart-item__quantity"> | |
| <span class="go-cart-item__quantity-label">Quantity: </span> | |
| <span class="go-cart-item__quantity-button js-go-cart-quantity-minus">-</span> | |
| <input class="go-cart-item__quantity-number js-go-cart-quantity" type="number" value="${item.quantity}" disabled> | |
| <span class="go-cart-item__quantity-button js-go-cart-quantity-plus">+</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="go-cart-item__price">${formatMoney(item.line_price)}</div> | |
| <a class="go-cart-item__remove ${this.removeFromCartNoDot}">Remove</a> | |
| </div> | |
| `; | |
| this.cartMiniCartContent.innerHTML += cartSingleProduct; | |
| }); | |
| this.cartMiniCartSubTotal.innerHTML = formatMoney(cart.total_price); | |
| this.cartMiniCartSubTotal.parentNode.classList.remove('is-invisible'); | |
| const removeFromCart = document.querySelectorAll(this.removeFromCart); | |
| removeFromCart.forEach((item) => { | |
| item.addEventListener('click', () => { | |
| GoCart.removeItemAnimation(item.parentNode); | |
| const line = item.parentNode.getAttribute('data-line'); | |
| this.removeItem(line); | |
| }); | |
| }); | |
| const itemQuantityPlus = document.querySelectorAll(this.itemQuantityPlus); | |
| itemQuantityPlus.forEach((item) => { | |
| item.addEventListener('click', () => { | |
| const line = item.parentNode.parentNode.parentNode.parentNode.getAttribute('data-line'); | |
| const quantity = Number(item.parentNode.querySelector(this.itemQuantity).value) + 1; | |
| this.changeItemQuantity(line, quantity); | |
| }); | |
| }); | |
| const itemQuantityMinus = document.querySelectorAll(this.itemQuantityMinus); | |
| itemQuantityMinus.forEach((item) => { | |
| item.addEventListener('click', () => { | |
| const line = item.parentNode.parentNode.parentNode.parentNode.getAttribute('data-line'); | |
| const quantity = Number(item.parentNode.querySelector(this.itemQuantity).value) - 1; | |
| this.changeItemQuantity(line, quantity); | |
| if (Number((item.parentNode.querySelector(this.itemQuantity).value - 1)) === 0) { | |
| GoCart.removeItemAnimation(item.parentNode.parentNode.parentNode.parentNode); | |
| } | |
| }); | |
| }); | |
| } | |
| renderBlankCartDrawer() { | |
| this.cartDrawerSubTotal.parentNode.classList.add('is-invisible'); | |
| this.clearCartDrawer(); | |
| this.cartDrawerContent.innerHTML = '<div class="go-cart__empty">Your Cart is currenty empty!</div>'; | |
| } | |
| renderBlankMiniCart() { | |
| this.cartMiniCartSubTotal.parentNode.classList.add('is-invisible'); | |
| this.clearMiniCart(); | |
| this.cartMiniCartContent.innerHTML = '<div class="go-cart__empty">Your Cart is currenty empty!</div>'; | |
| } | |
| clearCartDrawer() { | |
| this.cartDrawerContent.innerHTML = ''; | |
| } | |
| clearMiniCart() { | |
| this.cartMiniCartContent.innerHTML = ''; | |
| } | |
| clearCartModal() { | |
| this.cartModalContent.innerHTML = ''; | |
| } | |
| openCartDrawer() { | |
| this.cartDrawer.classList.add('is-open'); | |
| } | |
| closeCartDrawer() { | |
| this.cartDrawer.classList.remove('is-open'); | |
| } | |
| openMiniCart() { | |
| this.cartMiniCart.classList.add('is-open'); | |
| } | |
| closeMiniCart() { | |
| this.cartMiniCart.classList.remove('is-open'); | |
| } | |
| openFailModal() { | |
| this.cartModalFail.classList.add('is-open'); | |
| } | |
| closeFailModal() { | |
| this.cartModalFail.classList.remove('is-open'); | |
| } | |
| openCartModal() { | |
| this.cartModal.classList.add('is-open'); | |
| } | |
| closeCartModal() { | |
| this.cartModal.classList.remove('is-open'); | |
| } | |
| openCartOverlay() { | |
| this.cartOverlay.classList.add('is-open'); | |
| } | |
| closeCartOverlay() { | |
| this.cartOverlay.classList.remove('is-open'); | |
| } | |
| static removeItemAnimation(item) { | |
| item.classList.add('is-invisible'); | |
| } | |
| setDrawerDirection() { | |
| this.cartDrawer.classList.add(`go-cart__drawer--${this.drawerDirection}`); | |
| } | |
| } | |
| export default GoCart; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment