Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TH-109: Harmony > Prevent the customer from placing an order if a variant is out of stock #65

Merged
merged 8 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions themes/harmony/assets/add-to-cart.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
async function addToCart(snippetId) {
const parentSection = document.querySelector(`#s-${snippetId}`);
const variantId = parentSection.querySelector(`#variantId`)?.value || undefined;
const quantity = parentSection.querySelector(`#quantity`)?.value || 1;
const inventory = parentSection.querySelector(`#_inventory`)?.value || null;
const quantity = parseInt(parentSection.querySelector(`#quantity`)?.value) || 1;
const inventory = parseInt(parentSection.querySelector(`#_inventory`)?.value) || null;
const uploadedImageLink = parentSection.querySelector(`#yc-upload-link`)?.value || undefined;
const variantQuantityInCart = parseInt(document.querySelector('#cartQuantity')?.value) || null;

if (!variantId) {
return notify(ADD_TO_CART_EXPECTED_ERRORS.select_variant, 'error');
Expand All @@ -13,10 +14,14 @@ async function addToCart(snippetId) {
return notify(ADD_TO_CART_EXPECTED_ERRORS.quantity_smaller_than_zero, 'error');
}

if (inventory == 0) {
if (inventory === 0) {
return notify(ADD_TO_CART_EXPECTED_ERRORS.empty_inventory, 'error');
}

if (Number.isFinite(inventory) && ((variantQuantityInCart ?? 0) + quantity) > inventory) {
return notify(ADD_TO_CART_EXPECTED_ERRORS.max_quantity + inventory, 'warning');
}

try {
requestAnimationFrame(() => {
load('#loading__cart');
Expand All @@ -28,6 +33,8 @@ async function addToCart(snippetId) {
quantity,
});

await trackVariantQuantityOnCart(variantId);

if (response.error) throw new Error(response.error);

updateCartCount(response.count);
Expand Down Expand Up @@ -57,9 +64,11 @@ function attachRemoveItemListeners() {
const cartItemId = event.target.getAttribute('data-cart-item-id');
const productVariantId = event.target.getAttribute('data-product-variant-id');

await removeCartItem(cartItemId, productVariantId);
await updateCartDrawer();
updateCartCount(-1, true);
if(cartItemId && productVariantId) {
await removeCartItem(cartItemId, productVariantId);
await updateCartDrawer();
updateCartCount(-1, true);
}
})
);
}
Expand All @@ -74,6 +83,8 @@ async function removeCartItem(cartItemId, productVariantId) {
cartItemId,
productVariantId,
});

await trackVariantQuantityOnCart(productVariantId);
} catch (error) {
notify(error.message, 'error');
} finally {
Expand All @@ -97,6 +108,7 @@ async function updateCartItem(cartItemId, productVariantId, quantity) {
quantity,
});
await updateCartDrawer();
await trackVariantQuantityOnCart(productVariantId);
} catch (error) {
notify(error.message, 'error');
} finally {
Expand All @@ -105,7 +117,14 @@ async function updateCartItem(cartItemId, productVariantId, quantity) {
}
}

function increaseCartQuantity(cartItemId, productVariantId) {
function increaseCartQuantity(cartItemId, productVariantId, inventory) {
const input = document.querySelector(`#quantity-${cartItemId}`);
const currentQuantity = parseInt(input.value);

if (inventory && (currentQuantity >= inventory)) {
return notify(ADD_TO_CART_EXPECTED_ERRORS.max_quantity + inventory, 'warning');
}

updateCartQuantity(cartItemId, productVariantId, 1);
}

Expand All @@ -115,8 +134,10 @@ function decreaseCartQuantity(cartItemId, productVariantId) {

function updateCartQuantity(cartItemId, productVariantId, delta) {
const input = document.querySelector(`#quantity-${cartItemId}`);

if (input) {
const newQuantity = parseInt(input.value) + delta;

if (newQuantity >= 1) {
input.value = newQuantity;
updateCartItem(cartItemId, productVariantId, newQuantity);
Expand All @@ -133,6 +154,7 @@ function cartTemplate(item) {
}
}
const variationsString = variationsArray.join('<br/>');
const variantInventory = item.productVariant.product.track_inventory ? item.productVariant.inventory : null;

let variationsCheck = ''
if (variationsString === 'default: default') {
Expand Down Expand Up @@ -161,7 +183,7 @@ function cartTemplate(item) {
<div class="left-items">
<div class="product-price">
${
item.productVariant.compare_at_price ?
item.productVariant.compare_at_price ?
`<span class="compare-price">${item.productVariant.compare_at_price}</span>` : ''
}
<div class="currency-wrapper">
Expand All @@ -174,9 +196,9 @@ function cartTemplate(item) {
<div class="spinner" data-spinner-id="${item.id}" style="display: none;"></div>
<!--
<div class="quantity-control">
<button class="increase-btn cart-quantity-btn" onclick="increaseCartQuantity('${item.id}', '${item.productVariant.id}')">+</button>
<input type="number" id="quantity-${item.id}" value="${item.quantity}" min="1" onchange="updateCartItem('${item.id}', '${item.productVariant.id}', this.value)">
<button class="decrease-btn cart-quantity-btn" onclick="decreaseCartQuantity('${item.id}', '${item.productVariant.id}')">-</button>
<button class="increase-btn cart-quantity-btn" onclick="increaseCartQuantity('${item.id}', '${item.productVariant.id}', '${variantInventory}')">+</button>
<input type="number" id="quantity-${item.id}" value="${item.quantity}" min="1" onchange="updateCartItem('${item.id}', '${item.productVariant.id}', this.value)" oninput="restrictInputValue(event.target, ${variantInventory})">
<button class="decrease-btn cart-quantity-btn" onclick="decreaseCartQuantity('${item.id}', '${item.productVariant.id}', '${variantInventory}')">-</button>
</div>
-->
</div>
Expand Down Expand Up @@ -220,7 +242,7 @@ async function updateCartDrawer() {
if (item.productVariant.compare_at_price) {
const usePrecision = shouldUsePrecision(item.productVariant.compare_at_price);
item.productVariant.compare_at_price = formatCurrency(
item.productVariant.compare_at_price,
item.productVariant.compare_at_price,
currencyCode,
customerLocale,
);
Expand Down Expand Up @@ -348,13 +370,22 @@ function preventCartDrawerOpening(templateName) {
window.location.reload();
}

async function directAddToCart(event, productId) {
async function directAddToCart(event, productId, inventory, isTrackingInventory) {
event.preventDefault();

await trackVariantQuantityOnCart(productId);
const variantQuantityInCart = parseInt(document.querySelector('#cartQuantity')?.value) || null;
const isTrackingInventoryAvailable = Boolean(isTrackingInventory) && Number.isFinite(inventory);
const newQuantity = 1;

if (isTrackingInventoryAvailable && ((variantQuantityInCart ?? 0) + newQuantity) > inventory) {
return notify(ADD_TO_CART_EXPECTED_ERRORS.max_quantity + inventory, 'warning');
}

try {
const response = await youcanjs.cart.addItem({
productVariantId: productId,
quantity: 1
quantity: newQuantity
});

if (response.error) throw new Error(response.error);
Expand Down
39 changes: 21 additions & 18 deletions themes/harmony/assets/cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,23 +90,22 @@ async function removeCoupons(e) {
}
}

function updateCart(item, quantity, totalPriceSelector, cartItemId, productVariantId) {
function updateCart(item, quantity, totalPriceSelector, cartItemId, productVariantId, inventory) {
const inputHolder = document.getElementById(item);
const input = inputHolder.querySelector(`input[id="${productVariantId}"]`);
input.value = quantity;
const decrease = input.previousElementSibling;
const increase = input.nextElementSibling;

const productPrice = inputHolder.querySelector('.product-price');
const price = productPrice.innerText;
const totalPrice = inputHolder.querySelector(totalPriceSelector);

decrease
.querySelector('button')
.setAttribute('onclick', `decreaseQuantity('${cartItemId}', '${productVariantId}', '${Number(quantity) - 1}')`);
.setAttribute('onclick', `decreaseQuantity('${cartItemId}', '${productVariantId}', '${Number(quantity) - 1}', ${inventory})`);
increase
.querySelector('button')
.setAttribute('onclick', `increaseQuantity('${cartItemId}', '${productVariantId}', '${Number(quantity) + 1}')`);
.setAttribute('onclick', `increaseQuantity('${cartItemId}', '${productVariantId}', '${quantity}', ${inventory})`);

if (isNaN(quantity)) {
totalPrice.innerText = 0;
Expand Down Expand Up @@ -143,16 +142,16 @@ document.addEventListener('DOMContentLoaded', () => {
fetchCoupons();
});

function updateDOM(cartItemId, productVariantId, quantity) {
updateCart(cartItemId, quantity, '.total-price', cartItemId, productVariantId);
function updateDOM(cartItemId, productVariantId, quantity, inventory) {
updateCart(cartItemId, quantity, '.total-price', cartItemId, productVariantId, inventory);
updateTotalPrice();
}

function updatePrice(cartItemUniqueId, productVariantId, quantity) {
updateCart(`cart-item-${cartItemUniqueId}`, quantity, '.item-price', cartItemUniqueId, productVariantId);
function updatePrice(cartItemUniqueId, productVariantId, quantity, inventory) {
updateCart(`cart-item-${cartItemUniqueId}`, quantity, '.item-price', cartItemUniqueId, productVariantId, inventory);
}

async function updateQuantity(cartItemId, productVariantId, quantity) {
async function updateQuantity(cartItemId, productVariantId, quantity, inventory) {
load(`#loading__${cartItemId}`);
try {
await youcanjs.cart.updateItem({ cartItemId, productVariantId, quantity });
Expand All @@ -162,28 +161,32 @@ async function updateQuantity(cartItemId, productVariantId, quantity) {
stopLoad(`#loading__${cartItemId}`);
}

updateDOM(cartItemId, productVariantId, quantity);
updatePrice(cartItemId,productVariantId,quantity);
updateDOM(cartItemId, productVariantId, quantity, inventory);
updatePrice(cartItemId,productVariantId,quantity, inventory);
updateTotalPrice();
}

async function updateOnchange(cartItemId, productVariantId) {
async function updateOnchange(cartItemId, productVariantId, inventory) {
const inputHolder = document.getElementById(cartItemId);
const input = inputHolder.querySelector(`input[id="${productVariantId}"]`);
const quantity = input.value;

await updateQuantity(cartItemId, productVariantId, quantity);
await updateQuantity(cartItemId, productVariantId, quantity, inventory);
}

async function decreaseQuantity(cartItemId, productVariantId, quantity) {
if (quantity < 1) {
async function decreaseQuantity(cartItemId, productVariantId, quantity, inventory) {
if (Number(quantity) < 1) {
return;
}
await updateQuantity(cartItemId, productVariantId, quantity);
await updateQuantity(cartItemId, productVariantId, quantity, inventory);
}

async function increaseQuantity(cartItemId, productVariantId, quantity) {
await updateQuantity(cartItemId, productVariantId, quantity);
async function increaseQuantity(cartItemId, productVariantId, quantity, inventory) {
if (Number.isFinite(inventory) && (Number(quantity) >= inventory)) {
return notify(ADD_TO_CART_EXPECTED_ERRORS.max_quantity + inventory, 'warning');
}

await updateQuantity(cartItemId, productVariantId, (Number(quantity) + 1), inventory);
}

function updateCartItemCount(count) {
Expand Down
10 changes: 8 additions & 2 deletions themes/harmony/assets/dropdown-menu.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
let isDropDownOpened = false;
/**
* @param {HTMLElement} element
*/
function showDropDownMenu(element) {
element.classList.toggle('show');
isDropDownOpened = true;
}

/**
Expand All @@ -12,6 +14,7 @@ function showDropDownMenu(element) {
function hideDropDownMenu(element, event) {
if (!event.target.matches('.dropbtn, .dropbtn *')) {
element?.classList.remove('show');
isDropDownOpened = false;
}
}

Expand Down Expand Up @@ -43,7 +46,11 @@ function dropdownMenu() {
const dropdownContent = dropDownInput.querySelector('.dropdown-content');

selectInput.addEventListener('click', () => showDropDownMenu(dropdownContent));
window.addEventListener('click', (event) => hideDropDownMenu(dropdownContent, event));
document.addEventListener('click', (event) => {
if(isDropDownOpened) {
hideDropDownMenu(dropdownContent, event);
}
});

const selectOptions = dropdownContent.querySelectorAll('li');

Expand All @@ -62,5 +69,4 @@ function dropdownMenu() {
});
});
}

dropdownMenu();
9 changes: 4 additions & 5 deletions themes/harmony/assets/express-checkout.css
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
font-family:inherit;
font-weight:bold;
}
.express-checkout-button:disabled{
opacity:0.5;
cursor:not-allowed;
}
.express-checkout-button span{
font-family:inherit;
font-weight:inherit;
Expand Down Expand Up @@ -215,11 +219,6 @@
}
}

.sticky-checkout-placeholder .express-checkout-button:disabled{
opacity:0.5;
cursor:not-allowed;
}

.sticky-btn-placehodler{
opacity:0.5;
cursor:not-allowed;
Expand Down
1 change: 0 additions & 1 deletion themes/harmony/assets/express-checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ async function placeOrder() {
const formField = form.querySelector(`[name="${fieldName}"]`);
const errorEl = form.querySelector(`.validation-error[data-error="${fieldName}"]`);
if (formField) {
console.log(formField);
formField.classList.add('error');
}

Expand Down
3 changes: 3 additions & 0 deletions themes/harmony/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,9 @@ textarea{
.yc-alert.error{
background-color:var(--yc-error-color);
}
.yc-alert.warning{
background-color:var(--yc-warning-color);
}
.yc-alert.show{
opacity:1;
z-index:9999;
Expand Down
Loading