• I’ve taken the charge to update the Javascript and all our issues have been resolved. I don’t see a way to contribute (no github), so I’m uploading it here

    🔧 Major Fixes:

    1. Popup Issue Fixed:
      • Added event.stopPropagation() to prevent event bubbling
      • Check for existing popups before creating new ones
      • Improved overlay click handling with delay
    2. Better Event Management:
      • Proper event listener cleanup
      • Centralized popup closing function
      • Improved message handling
    3. Enhanced User Experience:
      • Better visual styling for locker details
      • Custom alert option for validation
      • Escape key support to close popup
      • Page visibility handling

    🎯 Key Features:

    • Popup Mode: Button that opens map in overlay
    • Embedded Mode: Map embedded directly in checkout
    • Multi-language Support: Greek and English
    • Country Support: Greece (GR) and Cyprus (CY)
    • Validation: Prevents order completion without locker selection
    • Persistence: Remembers selected locker in localStorage
    • Auto-cleanup: Clears selection when country/postal code changes

    🔄 How It Works:

    1. Initialization: Sets up button/embedded map based on settings
    2. Locker Selection: Opens appropriate map widget
    3. Data Handling: Receives locker data via postMessage API
    4. Display: Shows selected locker details with styling
    5. Validation: Ensures locker is selected before order placement
    6. Cleanup: Manages state when shipping method changes

    How to make the improvements:

    1. Head over to box-now-delivery plugin > js > box-now-delivery.js
    2. You can create a backup, if you wish or delete and re-install the plugin to revert changes later.
    3. Paste the code from below
    4. Clear any caching mechanisms such as Object Cache, etc.
    5. Try the checkout again
    (function ($) {
    /**
    * Add the Box Now Delivery button or embedded map.
    */
    function addButton() {
    if (
    $("#box_now_delivery_button").length === 0 &&
    boxNowDeliverySettings.displayMode === "popup"
    ) {
    var buttonText = boxNowDeliverySettings.buttonText || "Pick a locker";

    $('label[for="shipping_method_0_box_now_delivery"]').after(
    '<button type="button" id="box_now_delivery_button" style="display:none;">' +
    buttonText +
    "</button>"
    );

    attachButtonClickListener();
    } else if (boxNowDeliverySettings.displayMode === "embedded") {
    $('label[for="shipping_method_0_box_now_delivery"]').after(
    '<div id="box_now_delivery_embedded_map" style="display:none;"></div>'
    );
    embedMap();
    }
    applyButtonStyles();
    }

    /**
    * Apply the custom styles for the Box Now Delivery button.
    */
    function applyButtonStyles() {
    var buttonColor = boxNowDeliverySettings.buttonColor || "#84C33F";

    // Remove existing styles first to avoid duplicates
    $("#box-now-delivery-button-styles").remove();

    var styleBlock =
    <br> <style id="box-now-delivery-button-styles"><br> #box_now_delivery_button {<br> background-color: ${buttonColor} !important;<br> color: #fff !important;<br> padding: 8px 16px !important;<br> border: none !important;<br> border-radius: 4px !important;<br> cursor: pointer !important;<br> margin-left: 10px !important;<br> font-size: 14px !important;<br> }<br> #box_now_delivery_button:hover {<br> opacity: 0.9 !important;<br> }<br> </style><br>;

    $("head").append(styleBlock);
    }

    /**
    * Attach click event listener to the Box Now Delivery button.
    */
    function attachButtonClickListener() {
    $("#box_now_delivery_button").off("click").on("click", function (event) {
    event.preventDefault();
    event.stopPropagation(); // Prevent event bubbling

    // Check if popup already exists
    if ($("#box_now_delivery_overlay").length > 0) {
    return; // Don't create another popup
    }

    createPopupMap();
    });
    }

    /**
    * Get the selected country from billing form
    */
    function GetUserCountry() {
    // Get the selected country from the billing_country select input
    const selectedCountry = $('select[name="billing_country"]').val();
    return selectedCountry;
    }

    /**
    * Embed the map to the page.
    */
    function embedMap() {
    var iframe = $("#box_now_delivery_embedded_map iframe");

    if (iframe.length === 0) {
    iframe = createEmbeddedIframe();

    var lockerDetailsContainer = $("<div>", {
    id: "box_now_selected_locker_details",
    css: {
    display: "none",
    marginTop: "10px",
    },
    });

    // Create a new div to hold the locker information
    var lockerInfoContainer = $("<div>", {
    id: "locker_info_container",
    });

    $("#box_now_delivery_embedded_map")
    .css({
    position: "relative",
    width: "100%",
    height: "400px", // Set a fixed height for embedded map
    })
    .append(iframe)
    .append(lockerInfoContainer.append(lockerDetailsContainer));

    // Add the load event listener to the iframe
    iframe.on("load", function () {
    // Add the event listener for the embedded map
    const embeddedMessageHandler = function (event) {
    if (typeof event.data.boxnowClose !== "undefined") {
    // Handle the close event for embedded map
    } else if (typeof event.data === 'object' && event.data.boxnowLockerId) {
    updateLockerDetailsContainer(event.data);
    }
    };

    window.addEventListener("message", embeddedMessageHandler);
    });
    }

    if ($("#shipping_method_0_box_now_delivery").is(":checked")) {
    $("#box_now_delivery_embedded_map").show();
    } else {
    $("#box_now_delivery_embedded_map").hide();
    }
    }

    /**
    * Centralized popup closing function
    */
    function closePopup() {
    $("#box_now_delivery_overlay").remove();
    $("iframe[src^='https://widget-v5.boxnow.gr/popup.html']").remove();
    $("iframe[src^='https://widget-v5.boxnow.cy/popup.html']").remove();
    }

    /**
    * Create overlay for the popup iframe
    */
    function createOverlay() {
    // Remove any existing overlay first
    $("#box_now_delivery_overlay").remove();

    var overlay = $("<div>", {
    id: "box_now_delivery_overlay",
    css: {
    position: "fixed",
    top: 0,
    left: 0,
    width: "100%",
    height: "100%",
    backgroundColor: "rgba(0, 0, 0, 0.5)",
    zIndex: 9998,
    cursor: "pointer"
    },
    });

    // Add a small delay before attaching the click handler
    // This prevents immediate closure from event bubbling
    setTimeout(() => {
    overlay.on("click", function (e) {
    // Only close if clicking directly on overlay, not on child elements
    if (e.target === this) {
    closePopup();
    }
    });
    }, 100);

    $("body").append(overlay);
    }

    /**
    * Create an iframe for the popup map.
    */
    function createPopupMap() {
    // Remove any existing popup first
    closePopup();

    let gpsOption = boxNowDeliverySettings.gps_option;
    let partnerId = boxNowDeliverySettings.partnerId;
    let postalCode = $('input[name="billing_postcode"]').val();
    let country = GetUserCountry();
    console.log("Selected country:", country);

    let src;
    if (country === "CY") {
    src = "https://widget-v5.boxnow.cy/popup.html";
    } else {
    src = "https://widget-v5.boxnow.gr/popup.html";
    }

    // Build URL parameters properly
    let params = [];

    if (partnerId) {
    params.push("partnerId=" + partnerId);
    }

    if (gpsOption === "off") {
    params.push("gps=no");
    params.push("zip=" + encodeURIComponent(postalCode));
    params.push("autoclose=yes");
    params.push("autoselect=no");
    } else {
    params.push("gps=yes");
    params.push("autoclose=yes");
    params.push("autoselect=no");
    }

    if (params.length > 0) {
    src += "?" + params.join("&");
    }

    let iframe = $("<iframe>", {
    src: src,
    css: {
    position: "fixed",
    top: "50%",
    left: "50%",
    width: "90%",
    maxWidth: "800px",
    height: "80%",
    maxHeight: "600px",
    border: 0,
    borderRadius: "10px",
    transform: "translate(-50%, -50%)",
    zIndex: 9999,
    boxShadow: "0 4px 20px rgba(0,0,0,0.3)"
    },
    });

    // Improved message event listener
    const popupMessageHandler = function (event) {
    if (event.data === "closeIframe" ||
    (typeof event.data === 'object' && event.data.boxnowClose !== undefined)) {
    closePopup();
    window.removeEventListener("message", popupMessageHandler);
    } else if (typeof event.data === 'object' && event.data.boxnowLockerId) {
    updateLockerDetailsContainer(event.data);
    closePopup(); // Close popup after selection
    window.removeEventListener("message", popupMessageHandler);
    }
    };

    window.addEventListener("message", popupMessageHandler);

    createOverlay();
    $("body").append(iframe);
    }

    /**
    * Create an iframe for the embedded map.
    */
    function createEmbeddedIframe() {
    let gpsOption = boxNowDeliverySettings.gps_option;
    let partnerId = boxNowDeliverySettings.partnerId;
    let postalCode = $('input[name="billing_postcode"]').val();
    let country = GetUserCountry();

    let src;
    if (country === "CY") {
    src = "https://widget-v5.boxnow.cy";
    } else {
    src = "https://widget-v5.boxnow.gr";
    }

    // Build URL parameters properly
    let params = [];

    if (partnerId) {
    params.push("partnerId=" + partnerId);
    }

    if (gpsOption === "off") {
    params.push("gps=no");
    params.push("zip=" + encodeURIComponent(postalCode));
    } else {
    params.push("gps=yes");
    }

    if (params.length > 0) {
    src += "?" + params.join("&");
    }

    return $("<iframe>", {
    src: src,
    css: {
    width: "100%",
    height: "100%",
    border: 0,
    },
    });
    }

    /**
    * Update the locker details container with selected locker data.
    *
    * @param {object} lockerData Locker data object.
    */
    function updateLockerDetailsContainer(lockerData) {
    // Check if locker data is valid
    if (
    !lockerData ||
    lockerData.boxnowLockerId === undefined ||
    lockerData.boxnowLockerAddressLine1 === undefined ||
    lockerData.boxnowLockerPostalCode === undefined ||
    lockerData.boxnowLockerName === undefined
    ) {
    console.log("Invalid locker data received:", lockerData);
    return;
    }

    // Get the selected locker details
    var locker_id = lockerData.boxnowLockerId;
    var locker_address = lockerData.boxnowLockerAddressLine1;
    var locker_postal_code = lockerData.boxnowLockerPostalCode;
    var locker_name = lockerData.boxnowLockerName;

    // Store in localStorage
    localStorage.setItem("box_now_selected_locker", JSON.stringify(lockerData));

    // Ensure the locker details container exists
    if ($("#box_now_selected_locker_details").length === 0) {
    if (boxNowDeliverySettings.displayMode === "popup") {
    $("#box_now_delivery_button").after(
    '<div id="box_now_selected_locker_details" style="display:none;"></div>'
    );
    } else {
    $("#locker_info_container").append(
    '<div id="box_now_selected_locker_details" style="display:none;"></div>'
    );
    }
    }

    // Add or update hidden input field to store locker_id
    if ($("#_boxnow_locker_id").length === 0) {
    $("<input>")
    .attr({
    type: "hidden",
    id: "_boxnow_locker_id",
    name: "_boxnow_locker_id",
    value: locker_id,
    })
    .appendTo("#box_now_selected_locker_details");
    } else {
    $("#_boxnow_locker_id").val(locker_id);
    }

    // Get the language of the webpage
    var language = document.documentElement.lang || "el";

    // Define the content for English
    var englishContent = <br><div style="font-family: Arial, sans-serif; margin-top: 10px; padding: 15px; background-color: #f9f9f9; border-radius: 5px; border-left: 4px solid #84C33F;"><br> <p style="margin-bottom: 10px; color: #84C33F; font-size: 16px;"><b>✓ Selected Locker</b></p><br> <p style="margin-bottom: 5px; font-size: 14px;"><b>Locker Name:</b> ${locker_name}</p><br> <p style="margin-bottom: 5px; font-size: 14px;"><b>Address:</b> ${locker_address}</p><br> <p style="margin-bottom: 0; font-size: 14px;"><b>Postal Code:</b> ${locker_postal_code}</p><br></div>;

    // Define the content for Greek
    var greekContent = <br><div style="font-family: Arial, sans-serif; margin-top: 10px; padding: 15px; background-color: #f9f9f9; border-radius: 5px; border-left: 4px solid #84C33F;"><br> <p style="margin-bottom: 10px; color: #84C33F; font-size: 16px;"><b>✓ Επιλεγμένο Locker</b></p><br> <p style="margin-bottom: 5px; font-size: 14px;"><b>Όνομα Locker:</b> ${locker_name}</p><br> <p style="margin-bottom: 5px; font-size: 14px;"><b>Διεύθυνση:</b> ${locker_address}</p><br> <p style="margin-bottom: 0; font-size: 14px;"><b>ΤΚ:</b> ${locker_postal_code}</p><br></div>;

    // Choose the correct content based on the language
    var content = language === "el" ? greekContent : englishContent;

    // Update the locker details container
    $("#box_now_selected_locker_details").html(content).show();

    // Add or update hidden input field to store complete locker information
    if ($("#box_now_selected_locker_input").length === 0) {
    $("<input>")
    .attr({
    type: "hidden",
    id: "box_now_selected_locker_input",
    name: "box_now_selected_locker",
    value: JSON.stringify(lockerData),
    })
    .appendTo("#box_now_selected_locker_details");
    } else {
    $("#box_now_selected_locker_input").val(JSON.stringify(lockerData));
    }

    console.log("Locker details updated:", lockerData);
    }

    /**
    * Show the selected locker details from local storage.
    */
    function showSelectedLockerDetailsFromLocalStorage() {
    var lockerData = localStorage.getItem("box_now_selected_locker");

    if (lockerData) {
    try {
    updateLockerDetailsContainer(JSON.parse(lockerData));
    } catch (e) {
    console.error("Error parsing locker data from localStorage:", e);
    localStorage.removeItem("box_now_selected_locker");
    }
    }
    }

    /**
    * Toggle the Box Now Delivery button or embedded map based on the selected shipping method.
    */
    function toggleBoxNowDelivery() {
    if (boxNowDeliverySettings.displayMode === "popup") {
    toggleBoxNowDeliveryButton();
    } else if (boxNowDeliverySettings.displayMode === "embedded") {
    embedMap();
    }
    }

    /**
    * Toggle the Box Now Delivery button visibility based on the selected shipping method.
    */
    function toggleBoxNowDeliveryButton() {
    var boxButton = $("#box_now_delivery_button");
    var lockerDetails = $("#box_now_selected_locker_details");

    // Set the background color
    boxButton.css("background-color", boxNowDeliverySettings.buttonColor);

    if ($("#shipping_method_0_box_now_delivery").is(":checked")) {
    boxButton.show();
    showSelectedLockerDetailsFromLocalStorage();
    } else if ($('input[name="shipping_method[0]"]:checked').length > 0) {
    boxButton.hide();
    lockerDetails.hide();
    } else if (
    $('input[type="hidden"][name="shipping_method[0]"]').val() ===
    "box_now_delivery"
    ) {
    boxButton.show();
    showSelectedLockerDetailsFromLocalStorage();
    } else {
    boxButton.hide();
    lockerDetails.hide();
    }
    }

    /**
    * Remove the selected locker details from local storage and hide the locker details container
    */
    function clearSelectedLockerDetails() {
    localStorage.removeItem("box_now_selected_locker");
    $("#box_now_selected_locker_details").hide().empty();
    $("#_boxnow_locker_id").remove();
    $("#box_now_selected_locker_input").remove();
    console.log("Locker details cleared");
    }

    /**
    * Initialize the script.
    */
    function init() {
    addButton();
    toggleBoxNowDelivery();

    if ($("#shipping_method_0_box_now_delivery").is(":checked")) {
    showSelectedLockerDetailsFromLocalStorage();
    }
    }

    // Document ready event
    $(document).ready(function () {
    /**
    * Add validation for order placement to ensure locker selection.
    */
    function addOrderValidation() {
    $(document.body).on("click", "#place_order", function (event) {
    var lockerData = localStorage.getItem("box_now_selected_locker");

    if (
    !lockerData &&
    ($('input[type="radio"][name="shipping_method[0]"]:checked').val() ===
    "box_now_delivery" ||
    $('input[type="hidden"][name="shipping_method[0]"]').val() ===
    "box_now_delivery")
    ) {
    event.preventDefault();
    event.stopImmediatePropagation();

    var message = boxNowDeliverySettings.lockerNotSelectedMessage ||
    "Please select a locker first!";

    // Show a better styled alert
    if (typeof boxNowDeliverySettings.showCustomAlert !== 'undefined' &&
    boxNowDeliverySettings.showCustomAlert) {
    showCustomAlert(message);
    } else {
    alert(message);
    }

    return false;
    }
    });
    }

    /**
    * Show custom styled alert
    */
    function showCustomAlert(message) {
    var alertHtml = <br> <div id="box_now_alert_overlay" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); z-index: 10000; display: flex; align-items: center; justify-content: center;"><br> <div style="background: white; padding: 20px; border-radius: 10px; max-width: 400px; text-align: center; box-shadow: 0 4px 20px rgba(0,0,0,0.3);"><br> <p style="margin-bottom: 20px; font-size: 16px; color: #333;">${message}</p><br> <button onclick="$('#box_now_alert_overlay').remove()" style="background-color: #84C33F; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; font-size: 14px;">OK</button><br> </div><br> </div><br>;
    $('body').append(alertHtml);
    }

    // Initialize the plugin
    init();

    // Show the selected locker details from localStorage on page load
    showSelectedLockerDetailsFromLocalStorage();

    // Reinitialize when checkout is updated
    $(document.body).on("updated_checkout", function () {
    setTimeout(function() {
    init();
    }, 100);
    });

    // Handle shipping method changes
    $(document.body).on(
    "change",
    'input[type="radio"][name="shipping_method[0]"]',
    function() {
    setTimeout(function() {
    toggleBoxNowDelivery();
    }, 50);
    }
    );

    // Clear locker details when country changes
    $('body').on('change', '#billing_country', function(){
    clearSelectedLockerDetails();
    });

    // Clear locker details when postal code changes significantly
    var postalCodeTimeout;
    $('body').on('input', '#billing_postcode', function(){
    clearTimeout(postalCodeTimeout);
    postalCodeTimeout = setTimeout(function() {
    if ($("#shipping_method_0_box_now_delivery").is(":checked")) {
    clearSelectedLockerDetails();
    }
    }, 1000);
    });

    // Add order validation
    addOrderValidation();

    // Handle page visibility change (prevents issues with popups)
    $(document).on('visibilitychange', function() {
    if (document.hidden) {
    closePopup();
    }
    });

    // Close popup on escape key
    $(document).on('keydown', function(e) {
    if (e.key === 'Escape' && $("#box_now_delivery_overlay").length > 0) {
    closePopup();
    }
    });

    console.log("Box Now Delivery plugin initialized successfully");
    });

    })(jQuery);
Viewing 1 replies (of 1 total)
  • Really well done! Will be using this now. Just a heads up, the pasted code seems to have broken once pasted, with just some touch I fixed it and it’s now live on my website aswell!

Viewing 1 replies (of 1 total)

The topic ‘Major Fixes & Improvements [Custom Code]’ is closed to new replies.