All the necessary CSS & JS files for the site are located here. Make sure to have these JS files on codesandbox.io, as it significantly makes it easier pushing custom JS changes to the site.
INSIDE <head> tag
<!-- [Attributes by Finsweet] Disable scrolling -->
<script defer src="<https://cdn.jsdelivr.net/npm/@finsweet/attributes-scrolldisable@1/scrolldisable.js>"></script>
<!-- [Attributes by Finsweet] Mirror click events -->
<script defer src="<https://cdn.jsdelivr.net/npm/@finsweet/attributes-mirrorclick@1/mirrorclick.js>"></script>
<!-- Make sure to replace this with your wized code -->
<script src="<https://embed.wized.com/qwbbIwDD2paYu98LqXag.js>"></script>
<script data-wized-id="qwbbIwDD2paYu98LqXag" src="<https://embed.wized.com>"></script>
<style>
html.lenis {
height: auto;
}
.lenis.lenis-smooth {
scroll-behavior: auto;
}
.lenis.lenis-smooth [data-lenis-prevent] {
overscroll-behavior: contain;
}
.lenis.lenis-stopped {
overflow: hidden;
}
body .page-loader {display: block}
.w-editor .page-loader {display: none;}
.no-scroll-transition {overflow: hidden; position: relative;}
}
</style>
<script defer src="<https://cdn.jsdelivr.net/gh/studio-freight/[email protected]/bundled/lenis.min.js>"></script>
lenis.js
"use strict";
if (Webflow.env("editor") === undefined) {
// Check if viewport width is greater than 768 pixels
if (window.innerWidth > 468) {
window.lenis = new Lenis({
lerp: 0.1,
wheelMultiplier: 0.7,
infinite: false,
gestureOrientation: "vertical",
normalizeWheel: false,
smoothTouch: false
});
function raf(time) {
window.lenis.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
}
$("[data-lenis-start]").on("click", function () {
window.lenis && window.lenis.start();
});
$("[data-lenis-stop]").on("click", function () {
window.lenis && window.lenis.stop();
});
$("[data-lenis-toggle]").on("click", function () {
$(this).toggleClass("stop-scroll");
if ($(this).hasClass("stop-scroll")) {
window.lenis && window.lenis.stop();
} else {
window.lenis && window.lenis.start();
}
});
}
before </body> tag
cart.js
(function () {
// Ensure Wized is loaded.
if (typeof Wized === "undefined") {
console.error("Wized is not loaded yet");
return;
}
// Function to update the shipping bar based on the subtotal
const updateShippingBar = () => {
const subtotal = parseFloat(calculateSubtotalPrice());
const progressPercentage = Math.min((subtotal / 100) * 100, 100);
const shippingBarProgress = document.querySelector(
".shipping-progress-bar"
);
const remainingAmount = document.querySelector(
".free-shipping-text.remaining-amount"
);
const defaultText = document.querySelector(".shipping-text");
const successText = document.querySelector(".shipping-text.hide");
// Update the width of the progress bar.
shippingBarProgress.style.width = `${progressPercentage}%`;
// Update remaining amount and decide which text to display.
if (subtotal >= 100) {
defaultText.style.display = "none";
successText.style.display = "flex";
} else {
const amountRemaining = (100 - subtotal).toFixed(2);
remainingAmount.textContent = `£${amountRemaining}`;
defaultText.style.display = "flex";
successText.style.display = "none";
}
};
// Define local storage key for products in cart
window.LOCAL_STORAGE_KEY = "wized_products_in_cart";
const TIMESTAMP_KEY = "wized_cart_timestamp";
// Function to update the cart empty status
const updateCartEmptyStatus = async () => {
const storedProducts = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
const isEmpty = storedProducts.length === 0;
await Wized.data.setVariable("cartEmpty", isEmpty);
};
// Function to store product details in local storage
const storeProductInLocalStorage = (productDetails) => {
const products = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
const existingProduct = products.find(
(product) => product.id === productDetails.id
);
if (existingProduct) {
existingProduct.quantity = productDetails.quantity;
} else {
products.push(productDetails);
}
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(products));
localStorage.setItem(TIMESTAMP_KEY, Date.now().toString());
};
// Function to remove product from local storage
const removeProductFromLocalStorage = (productId) => {
let products = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) || "[]");
products = products.filter((product) => product.id !== productId);
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(products));
};
const updateProductQuantityInLocalStorage = (productId, newQuantity) => {
const products = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
const productToUpdate = products.find(
(product) => product.id === productId
);
if (productToUpdate) {
productToUpdate.quantity = newQuantity;
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(products));
}
};
const getQuantityFromLocalStorage = (productId) => {
const products = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
const product = products.find((product) => product.id === productId);
return product ? product.quantity : 1;
};
const updateQuantityInputForProduct = (productId) => {
const inputElement = document.querySelector(
`[wized="cart_item"][data-attribute-id="${productId}"] [wized="cart_item_quantity"]`
);
if (inputElement) {
const quantity = getQuantityFromLocalStorage(productId);
inputElement.value = quantity;
} else {
console.error(`No input element found for product ID: ${productId}`);
}
};
const calculateTotalQuantity = () => {
const products = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
return products.reduce((total, product) => total + product.quantity, 0);
};
const calculateSubtotalPrice = () => {
const products = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
return products
.reduce((total, product) => {
const priceValue = parseFloat(product.price.replace("£", ""));
return total + priceValue * product.quantity;
}, 0)
.toFixed(2);
};
const updateDisplayedTotals = () => {
const totalQuantityElem = document.querySelector(
'[wized="item_quantity_total"]'
);
const subtotalPriceElem = document.querySelector(
'[wized="subtotal_price"]'
);
totalQuantityElem.textContent = calculateTotalQuantity();
subtotalPriceElem.textContent = `£${calculateSubtotalPrice()}`;
};
const MAX_RETRIES = 10;
const RETRY_INTERVAL = 1000;
const pollForCartItems = async (storedProducts) => {
let retryCount = 0;
const pollInterval = setInterval(() => {
const storedProductIds = storedProducts.map((product) => product.id);
const foundAllItems = storedProductIds.every((productId) => {
const inputElement = document.querySelector(
`[wized="cart_item"][data-attribute-id="${productId}"] [wized="cart_item_quantity"]`
);
return inputElement !== null;
});
if (foundAllItems || retryCount >= MAX_RETRIES) {
clearInterval(pollInterval);
if (foundAllItems) {
storedProductIds.forEach(updateQuantityInputForProduct);
updateDisplayedTotals();
}
} else {
retryCount++;
}
}, RETRY_INTERVAL);
};
const updateCartAndPollItems = async () => {
const storedProducts = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
await updateCartIds(); // Get the product IDs
await Wized.request.execute("Fetch Cart Items"); // Fetch cart items
await pollForCartItems(storedProducts); // Poll for cart items
await updateCartEmptyStatus();
};
const handleCurrentProductDetailsUpdate = async () => {
const currentProductDetails = await Wized.data.get(
"v.currentProductDetails"
);
const storedProducts = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
const existingProduct = storedProducts.find(
(product) => product.id === currentProductDetails.id
);
// If the product already exists in the cart, we bypass the logic to add it again.
if (existingProduct) return;
if (currentProductDetails && currentProductDetails.id) {
storeProductInLocalStorage({
...currentProductDetails,
quantity: 1
});
await updateCartAndPollItems();
updateQuantityInputForProduct(currentProductDetails.id);
// Update the displayed totals and shipping bar
updateDisplayedTotals();
updateShippingBar();
}
};
Wized.data.listen(
"v.currentProductDetails",
handleCurrentProductDetailsUpdate
);
const updateCartIds = async () => {
const storedProducts = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
const cartIds = storedProducts.map((product) => product.id);
await Wized.data.setVariable("cartIds", JSON.stringify(cartIds));
};
document.addEventListener("DOMContentLoaded", async () => {
const timestamp = localStorage.getItem(TIMESTAMP_KEY);
const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1000;
if (timestamp && Date.now() - timestamp > SEVEN_DAYS) {
localStorage.removeItem(LOCAL_STORAGE_KEY);
localStorage.removeItem(TIMESTAMP_KEY);
}
await updateCartAndPollItems();
const storedProducts = JSON.parse(
localStorage.getItem(LOCAL_STORAGE_KEY) || "[]"
);
setTimeout(() => {
storedProducts.forEach((product) => {
updateQuantityInputForProduct(product.id);
});
updateDisplayedTotals();
}, 1000);
const subtotalElement = document.querySelector('[wized="subtotal_price"]');
if (storedProducts.length === 0 && subtotalElement) {
subtotalElement.textContent = "£0.00";
}
updateShippingBar();
});
document.body.addEventListener("click", async (event) => {
const targetElement = event.target;
const productDiv = targetElement.closest('[wized="cart_item"]');
if (!productDiv) return;
const inputElement = productDiv.querySelector(
'[wized="cart_item_quantity"]'
);
const productId = productDiv.getAttribute("data-attribute-id");
if (targetElement.closest('[wized="cart_decreament"]')) {
let currentQuantity = parseInt(inputElement.value, 10) || 0;
if (currentQuantity > 1) {
inputElement.value = currentQuantity - 1;
updateProductQuantityInLocalStorage(productId, currentQuantity - 1);
}
} else if (targetElement.closest('[wized="cart_increament"]')) {
let currentQuantity = parseInt(inputElement.value, 10);
inputElement.value = currentQuantity + 1;
updateProductQuantityInLocalStorage(productId, currentQuantity + 1);
} else if (targetElement.closest('[wized="cart_remove_item"]')) {
removeProductFromLocalStorage(productId);
await updateCartIds();
// Here, we execute the fetch after updating the cartIds
await Wized.request.execute("Fetch Cart Items");
}
await pollForCartItems(
JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) || "[]")
);
updateDisplayedTotals();
updateShippingBar();
await updateCartEmptyStatus();
});
// Function to handle manual quantity update
const handleManualQuantityUpdate = async (inputElement, productId) => {
const newQuantity = parseInt(inputElement.value, 10);
if (isNaN(newQuantity) || newQuantity < 1) {
// Reset to the previous quantity if the input is not valid.
inputElement.value = getQuantityFromLocalStorage(productId);
return;
}
updateProductQuantityInLocalStorage(productId, newQuantity);
updateDisplayedTotals();
updateShippingBar();
await updateCartEmptyStatus();
};
// Event listener for input events to handle manual quantity updates
document.body.addEventListener("input", (event) => {
const inputElement = event.target;
if (inputElement.matches('[wized="cart_item_quantity"]')) {
const productDiv = inputElement.closest('[wized="cart_item"]');
if (!productDiv) return;
const productId = productDiv.getAttribute("data-attribute-id");
handleManualQuantityUpdate(inputElement, productId);
}
});
// Listen for updates to the current product details and call updateCartAndPollItems function
Wized.data.listen("v.currentProductDetails", updateCartAndPollItems);
})();
checkout.js
document.body.addEventListener("click", async (event) => {
const targetElement = event.target;
if (targetElement.closest('[wized="checkout_button"]')) {
const storedProducts = JSON.parse(
localStorage.getItem(window.LOCAL_STORAGE_KEY) || "[]"
);
const lineItems = storedProducts.map((product) => {
return {
variantId: product.productVariantId,
quantity: product.quantity
};
});
// Convert to the GraphQL format
const formattedLineItems = lineItems
.map(
(item) => `{variantId: "${item.variantId}", quantity: ${item.quantity}}`
)
.join(", ");
// Set the Wized variable
await Wized.data.setVariable("checkoutItems", `[${formattedLineItems}]`);
// Execute the Wized request
await Wized.request.execute("Create Checkout");
// Get the checkout URL
const checkoutURL = await Wized.data.get(
"r.7.d.data.data.checkoutCreate.checkout.webUrl"
);
// Redirect the user to the checkout URL
if (checkoutURL) {
window.location.href = checkoutURL;
} else {
console.error("Failed to retrieve checkout URL");
}
}
});
INSIDE <head> tag