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.

01. Project Settings

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");
    }
  }
});

02. /homepage

INSIDE <head> tag