Skip to content

Instantly share code, notes, and snippets.

@NicolaBizzoca
Created April 21, 2022 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NicolaBizzoca/6da236236b80455d497580d4831799be to your computer and use it in GitHub Desktop.
Save NicolaBizzoca/6da236236b80455d497580d4831799be to your computer and use it in GitHub Desktop.
<script>
(function () {
function getCheckoutButtons() {
return Array.from(document.querySelectorAll('[name=checkout], [href*=checkout]:not([href*=\'/tools/checkout/front_end/login\']), [action*=checkout] [type=submit], [onclick*=checkout], .additional-checkout-button:not(.additional-checkout-button--apple-pay)'));
}
function getCart(callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/cart.json', true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200 && callback) {
callback(JSON.parse(xhr.responseText));
}
}
xhr.send();
}
function variantsToHave(item) {
return item.properties && item.properties['_configurationVariants'] && JSON.parse(item.properties['_configurationVariants']) || [];
}
function handleQty(qty, variants) {
return [].concat.apply([], Array(qty).fill(variants));
}
function getVariants(items) {
return items.reduce((acc, val) => acc.concat(val), []).reduce(function (acc, variant) {
acc[variant] = (acc[variant] || 0) + 1;
return acc;
}, {});
}
function diff(toHave, current) {
return Object.keys(toHave).reduce(function (acc, item) {
acc[item] = toHave[item] - (current[item] || 0);
return acc;
}, {});
}
function nonZeroQty(cartDiff) {
return Object.keys(cartDiff).reduce(function (acc, item) {
if (cartDiff[item]) {
acc[item] = cartDiff[item];
}
return acc;
}, {});
}
function zeroQty(cartDiff) {
return Object.keys(cartDiff).reduce(function (acc, item) {
acc[item] = 0;
return acc;
}, {});
}
function asCartUpdate(cartDiff) {
return {
updates: cartDiff
};
}
function updateCart(toUpdate, callback) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/cart/update.js', true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200 && callback) {
callback();
}
}
xhr.send(JSON.stringify(toUpdate));
}
function toUpdate(cart) {
var variants = getVariants(cart.items.map(function (item) {
return handleQty(item.quantity, variantsToHave(item));
}));
var currentVariants = cart.items.filter(function (item) {
return Object.keys(variants).map(function (id) {
return Number.parseInt(id);
}).includes(item.id);
}).reduce(function (acc, item) {
acc[item.id] = item.quantity;
return acc;
}, {});
return diff(variants, currentVariants);
}
function toUpdateZero(cart) {
var variants = getVariants(cart.items.map(function (item) {
return handleQty(item.quantity, variantsToHave(item));
}));
var currentVariants = cart.items.filter(function (item) {
return Object.keys(variants).map(function (id) {
return Number.parseInt(id);
}).includes(item.id);
}).reduce(function (acc, item) {
acc[item.id] = item.quantity;
return acc;
}, {});
return currentVariants;
}
function needUpdate(update) {
return Object.keys(update.updates).length > 0;
}
function needUpdateZero(update) {
const keys = Object.keys(update.updates);
return keys.length > 0 && keys.every(k => k > 0);
}
function needReload() {
window.location.reload(false);
}
document.addEventListener('DOMContentLoaded', function () {
getCheckoutButtons().forEach(function (button) {
var zakekeHandled = false;
button.addEventListener('click', function (e) {
if (zakekeHandled) {
return;
}
e.preventDefault();
getCart(function(cart) {
var cartUpdate = asCartUpdate(nonZeroQty(toUpdate(cart)));
if (needUpdate(cartUpdate)) {
updateCart(cartUpdate, function () {
zakekeHandled = true;
e.target.click();
});
} else {
zakekeHandled = true;
e.target.click();
}
});
});
});
});
if (!window.location.pathname.includes('/cart')) {
getCart(function(cart) {
var cartUpdate = asCartUpdate(nonZeroQty(toUpdate(cart)));
if (needUpdate(cartUpdate)) {
updateCart(cartUpdate);
}
});
} else {
getCart(function (cart) {
var cartUpdate = asCartUpdate(zeroQty(toUpdateZero(cart)));
if (needUpdate(cartUpdate)) {
updateCart(cartUpdate, needReload);
}
});
}
})();
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment