2001 lines
85 KiB
JavaScript
2001 lines
85 KiB
JavaScript
/*
|
|
* Copyright 2025 Criptomart
|
|
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
*/
|
|
|
|
(function () {
|
|
"use strict";
|
|
|
|
// Objeto global para gestión de carrito
|
|
window.groupOrderShop = {
|
|
orderId: null,
|
|
cart: {},
|
|
labels: {}, // Will be loaded from HTML data attributes
|
|
|
|
init: function () {
|
|
console.log("[groupOrderShop] Initializing...");
|
|
|
|
var self = this;
|
|
|
|
// Get order ID first (needed by i18nManager and other functions)
|
|
var confirmBtn = document.getElementById("confirm-order-btn");
|
|
var cartContainer = document.getElementById("cart-items-container");
|
|
|
|
var orderIdElement = confirmBtn || cartContainer;
|
|
if (!orderIdElement) {
|
|
console.log("No elements found to get order ID");
|
|
return false;
|
|
}
|
|
|
|
// Get the order ID from the data attribute or from the URL
|
|
this.orderId = orderIdElement.getAttribute("data-order-id");
|
|
if (!this.orderId) {
|
|
var urlMatch = window.location.pathname.match(/\/eskaera\/(\d+)/);
|
|
this.orderId = urlMatch ? urlMatch[1] : null;
|
|
}
|
|
|
|
if (!this.orderId) {
|
|
console.error("Order ID not found");
|
|
if (cartContainer) {
|
|
cartContainer.innerHTML =
|
|
'<div class="alert alert-danger">' + "Error: Order ID not found</div>";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
console.log("Initializing cart for order:", this.orderId);
|
|
|
|
// Attach event listeners FIRST (doesn't depend on translations)
|
|
this._attachEventListeners();
|
|
console.log("[groupOrderShop] Event listeners attached");
|
|
|
|
// Wait for i18nManager to load translations from server
|
|
i18nManager
|
|
.init()
|
|
.then(function () {
|
|
console.log("[groupOrderShop] Translations loaded from server");
|
|
self.labels = i18nManager.getAll();
|
|
|
|
self._checkGroupOrderStatus(function () {
|
|
self._loadCart();
|
|
self._checkConfirmationMessage();
|
|
self._initializeTooltips();
|
|
|
|
// Update display if there is cart-items-container
|
|
if (cartContainer) {
|
|
self._updateCartDisplay();
|
|
}
|
|
|
|
// Check if we're loading from history
|
|
var storageKey = "load_from_history_" + self.orderId;
|
|
if (sessionStorage.getItem(storageKey)) {
|
|
// Load items from historical order
|
|
self._loadFromHistory();
|
|
} else {
|
|
// Auto-load draft order on page load (silent mode)
|
|
self._autoLoadDraftOnInit();
|
|
}
|
|
|
|
// Emit event when fully initialized
|
|
document.dispatchEvent(
|
|
new CustomEvent("groupOrderShopReady", {
|
|
detail: { labels: self.labels },
|
|
})
|
|
);
|
|
|
|
console.log("[groupOrderShop] ✓ Initialization complete");
|
|
});
|
|
})
|
|
.catch(function (error) {
|
|
console.error("[groupOrderShop] Failed to initialize translations:", error);
|
|
// Fallback: use empty labels so app doesn't crash
|
|
self.labels = {};
|
|
});
|
|
|
|
// Dispatch event to notify that cart is ready (preliminary, will be fired again when translations loaded)
|
|
var event = new CustomEvent("groupOrderCartReady", {
|
|
detail: { orderId: this.orderId },
|
|
});
|
|
document.dispatchEvent(event);
|
|
console.log("Cart ready event dispatched for order:", this.orderId);
|
|
|
|
return true;
|
|
},
|
|
|
|
_checkConfirmationMessage: function () {
|
|
// Removed: this was showing confirmation message again in eskaera page
|
|
// which confused the user. The message is shown only in the checkout page
|
|
// before redirecting.
|
|
var confirmationMessage = sessionStorage.getItem("confirmation_message");
|
|
if (confirmationMessage) {
|
|
// Just remove it, don't show it again
|
|
sessionStorage.removeItem("confirmation_message");
|
|
}
|
|
},
|
|
|
|
_autoLoadDraftOnInit: function () {
|
|
console.log("Attempting to auto-load draft order...");
|
|
var self = this;
|
|
|
|
// Only auto-load if cart is empty
|
|
var cartItemsCount = Object.keys(this.cart).length;
|
|
if (cartItemsCount > 0) {
|
|
console.log("Cart already has items (" + cartItemsCount + "), skipping auto-load");
|
|
return;
|
|
}
|
|
|
|
var orderData = {
|
|
order_id: this.orderId,
|
|
};
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("POST", "/eskaera/load-draft", true);
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
try {
|
|
var data = JSON.parse(xhr.responseText);
|
|
if (data.success) {
|
|
// Clear current cart
|
|
self.cart = {};
|
|
|
|
// Load items from draft order
|
|
var items = data.items || [];
|
|
items.forEach(function (item) {
|
|
var productId = item.product_id;
|
|
self.cart[productId] = {
|
|
name: item.product_name,
|
|
price: item.product_price,
|
|
qty: item.quantity,
|
|
};
|
|
});
|
|
|
|
// Save to localStorage
|
|
self._saveCart();
|
|
|
|
// Restore pickup fields if available
|
|
if (data.pickup_day) {
|
|
var dayElement = document.getElementById("pickup-day");
|
|
if (dayElement) {
|
|
dayElement.value = data.pickup_day;
|
|
console.log("Auto-loaded pickup_day:", data.pickup_day);
|
|
}
|
|
}
|
|
|
|
if (data.pickup_date) {
|
|
var dateElement = document.getElementById("pickup-date");
|
|
if (dateElement) {
|
|
dateElement.value = data.pickup_date;
|
|
console.log("Auto-loaded pickup_date:", data.pickup_date);
|
|
}
|
|
}
|
|
|
|
if (data.home_delivery !== undefined) {
|
|
var homeDeliveryElement =
|
|
document.getElementById("home-delivery-checkbox");
|
|
if (homeDeliveryElement) {
|
|
homeDeliveryElement.checked = data.home_delivery;
|
|
console.log("Auto-loaded home_delivery:", data.home_delivery);
|
|
}
|
|
}
|
|
|
|
// Update display
|
|
self._updateCartDisplay();
|
|
|
|
console.log("Auto-loaded " + items.length + " items from draft");
|
|
// Show a subtle notification
|
|
var labels = self._getLabels();
|
|
var cartRestoredMsg =
|
|
(labels.cart_restored || "Your cart has been restored") +
|
|
" (" +
|
|
items.length +
|
|
" items)";
|
|
self._showNotification("✓ " + cartRestoredMsg, "info", 3000);
|
|
} else {
|
|
// Silently ignore - no draft found (normal case)
|
|
console.log("No draft found to auto-load (normal)");
|
|
}
|
|
} catch (e) {
|
|
console.error("Error parsing auto-load response:", e);
|
|
}
|
|
} else if (xhr.status === 404) {
|
|
// No draft found - this is normal, not an error
|
|
console.log("No draft order found (404 - normal)");
|
|
} else {
|
|
console.log("Auto-load failed with status:", xhr.status);
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
console.log("Auto-load connection error (non-critical)");
|
|
};
|
|
|
|
xhr.send(JSON.stringify(orderData));
|
|
},
|
|
|
|
_loadFromHistory: function () {
|
|
// Load items from historical order (called from load_from_history page)
|
|
var self = this;
|
|
var storageKey = "load_from_history_" + this.orderId;
|
|
var orderNameKey = "load_from_history_order_name_" + this.orderId;
|
|
var pickupDayKey = "load_from_history_pickup_day_" + this.orderId;
|
|
var pickupDateKey = "load_from_history_pickup_date_" + this.orderId;
|
|
var homeDeliveryKey = "load_from_history_home_delivery_" + this.orderId;
|
|
|
|
var itemsJson = sessionStorage.getItem(storageKey);
|
|
var orderName = sessionStorage.getItem(orderNameKey);
|
|
var pickupDay = sessionStorage.getItem(pickupDayKey);
|
|
var pickupDate = sessionStorage.getItem(pickupDateKey);
|
|
var homeDelivery = sessionStorage.getItem(homeDeliveryKey) === "true";
|
|
|
|
console.log("DEBUG: _loadFromHistory called for orderId:", this.orderId);
|
|
console.log("DEBUG: sessionStorageKey:", storageKey);
|
|
console.log("DEBUG: sessionStorage value type:", typeof itemsJson, "value:", itemsJson);
|
|
console.log("DEBUG: orderName:", orderName);
|
|
console.log("DEBUG: pickupDay:", pickupDay, "(empty means different group order)");
|
|
console.log("DEBUG: pickupDate:", pickupDate, "(empty means different group order)");
|
|
console.log(
|
|
"DEBUG: homeDelivery:",
|
|
homeDelivery,
|
|
"(empty means different group order)"
|
|
);
|
|
|
|
if (!itemsJson || itemsJson === "[object Object]") {
|
|
console.log("No valid items from history found in sessionStorage");
|
|
sessionStorage.removeItem(storageKey);
|
|
sessionStorage.removeItem(orderNameKey);
|
|
sessionStorage.removeItem(pickupDayKey);
|
|
sessionStorage.removeItem(pickupDateKey);
|
|
sessionStorage.removeItem(homeDeliveryKey);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Ensure itemsJson is a string before parsing
|
|
if (typeof itemsJson !== "string") {
|
|
console.log("itemsJson is not a string, converting...");
|
|
itemsJson = JSON.stringify(itemsJson);
|
|
}
|
|
|
|
// Parse items
|
|
var items = JSON.parse(itemsJson);
|
|
|
|
// Verify we got an array
|
|
if (!Array.isArray(items)) {
|
|
console.error("Parsed items is not an array:", items);
|
|
sessionStorage.removeItem(storageKey);
|
|
sessionStorage.removeItem(orderNameKey);
|
|
sessionStorage.removeItem(pickupDayKey);
|
|
sessionStorage.removeItem(pickupDateKey);
|
|
sessionStorage.removeItem(homeDeliveryKey);
|
|
return;
|
|
}
|
|
|
|
console.log("Loaded " + items.length + " items from history:", items);
|
|
|
|
// Clear current cart
|
|
this.cart = {};
|
|
console.log("Cart cleared, now empty");
|
|
|
|
// Add each item to cart
|
|
items.forEach(function (item) {
|
|
self.cart[item.product_id] = {
|
|
name: item.product_name || "Product " + item.product_id,
|
|
price: item.price || 0,
|
|
qty: item.quantity || 1,
|
|
};
|
|
console.log(
|
|
"Added to cart: product_id=" + item.product_id + ", qty=" + item.quantity
|
|
);
|
|
});
|
|
|
|
console.log("Cart after adding all items:", self.cart);
|
|
|
|
// Save to localStorage
|
|
this._saveCart();
|
|
console.log(
|
|
"After _saveCart(), localStorage contains:",
|
|
localStorage.getItem("eskaera_" + this.orderId + "_cart")
|
|
);
|
|
|
|
// Restore pickup fields if available (non-empty)
|
|
// Empty values mean the order was from a different group order,
|
|
// so we use the current group order's pickup fields instead
|
|
if (pickupDay && pickupDay.trim() !== "") {
|
|
var dayElement = document.getElementById("pickup-day");
|
|
if (dayElement) {
|
|
dayElement.value = pickupDay;
|
|
console.log("Restored pickup_day from old order:", pickupDay);
|
|
}
|
|
} else {
|
|
console.log(
|
|
"Did NOT restore pickup_day (empty = different group order, using current group order days)"
|
|
);
|
|
}
|
|
|
|
if (pickupDate && pickupDate.trim() !== "") {
|
|
var dateElement = document.getElementById("pickup-date");
|
|
if (dateElement) {
|
|
dateElement.value = pickupDate;
|
|
console.log("Restored pickup_date from old order:", pickupDate);
|
|
}
|
|
} else {
|
|
console.log("Did NOT restore pickup_date (empty = different group order)");
|
|
}
|
|
|
|
if (homeDelivery !== null && homeDelivery !== false) {
|
|
var homeDeliveryElement = document.getElementById("home-delivery-checkbox");
|
|
if (homeDeliveryElement) {
|
|
homeDeliveryElement.checked = homeDelivery;
|
|
console.log("Restored home_delivery from old order:", homeDelivery);
|
|
}
|
|
} else {
|
|
console.log(
|
|
"Did NOT restore home_delivery (empty/false = different group order or not set)"
|
|
);
|
|
}
|
|
|
|
// Update display
|
|
this._updateCartDisplay();
|
|
|
|
// Show notification with order reference if available
|
|
var labels = this._getLabels();
|
|
var itemsLabel = labels.items || "items";
|
|
var orderLoadedMsg = labels.order_loaded || "Order loaded";
|
|
var message = "✓ " + orderLoadedMsg + " (" + items.length + " " + itemsLabel + ")";
|
|
if (orderName) {
|
|
message += " - " + orderName;
|
|
}
|
|
this._showNotification(message, "success", 3000);
|
|
|
|
// Clear sessionStorage
|
|
sessionStorage.removeItem(storageKey);
|
|
sessionStorage.removeItem(orderNameKey);
|
|
sessionStorage.removeItem(pickupDayKey);
|
|
sessionStorage.removeItem(pickupDateKey);
|
|
sessionStorage.removeItem(homeDeliveryKey);
|
|
} catch (e) {
|
|
console.error("Error loading from history:", e);
|
|
console.error("itemsJson was:", itemsJson);
|
|
// Don't show error to user if sessionStorage had invalid data - just continue
|
|
sessionStorage.removeItem(storageKey);
|
|
sessionStorage.removeItem(orderNameKey);
|
|
sessionStorage.removeItem(pickupDayKey);
|
|
sessionStorage.removeItem(pickupDateKey);
|
|
sessionStorage.removeItem(homeDeliveryKey);
|
|
// Only show notification if we actually tried to load something
|
|
if (itemsJson && itemsJson !== "[object Object]") {
|
|
this._showNotification("Error loading order: " + e.message, "danger");
|
|
}
|
|
}
|
|
},
|
|
|
|
_loadCart: function () {
|
|
var cartKey = "eskaera_" + this.orderId + "_cart";
|
|
var savedCart = localStorage.getItem(cartKey);
|
|
this.cart = savedCart ? JSON.parse(savedCart) : {};
|
|
console.log("Cart loaded from localStorage[" + cartKey + "]:", this.cart);
|
|
console.log("Raw localStorage value:", savedCart);
|
|
},
|
|
|
|
_saveCart: function () {
|
|
var cartKey = "eskaera_" + this.orderId + "_cart";
|
|
var cartJson = JSON.stringify(this.cart);
|
|
localStorage.setItem(cartKey, cartJson);
|
|
console.log("Cart saved to localStorage[" + cartKey + "]:", this.cart);
|
|
console.log("Verification - immediately read back:", localStorage.getItem(cartKey));
|
|
},
|
|
|
|
_clearCurrentOrderCartSilently: function () {
|
|
var cartKey = "eskaera_" + this.orderId + "_cart";
|
|
localStorage.removeItem(cartKey);
|
|
this.cart = {};
|
|
console.log("[groupOrderShop] Cart cleared silently for order:", this.orderId);
|
|
},
|
|
|
|
_isClosedOrderResponse: function (xhr) {
|
|
if (!xhr) {
|
|
return false;
|
|
}
|
|
|
|
if (xhr.status !== 400 && xhr.status !== 403) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
var errorData = JSON.parse(xhr.responseText || "{}");
|
|
return (
|
|
errorData.code === "group_order_not_open" ||
|
|
errorData.action === "clear_cart" ||
|
|
errorData.order_state === "closed" ||
|
|
errorData.order_state === "cancelled"
|
|
);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
_checkGroupOrderStatus: function (callback) {
|
|
var self = this;
|
|
var done = function () {
|
|
if (typeof callback === "function") {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("POST", "/eskaera/check-status", true);
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
xhr.onload = function () {
|
|
if (xhr.status !== 200) {
|
|
done();
|
|
return;
|
|
}
|
|
try {
|
|
var data = JSON.parse(xhr.responseText || "{}");
|
|
if (data && data.is_open === false) {
|
|
self._clearCurrentOrderCartSilently();
|
|
}
|
|
} catch (e) {
|
|
console.warn("[groupOrderShop] check-status parse error", e);
|
|
}
|
|
done();
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
done();
|
|
};
|
|
|
|
xhr.send(
|
|
JSON.stringify({
|
|
order_id: this.orderId,
|
|
})
|
|
);
|
|
},
|
|
|
|
_showNotification: function (message, type, duration) {
|
|
// type: 'success', 'error', 'warning', 'info'
|
|
// duration: milliseconds (default 8000 = 8 seconds)
|
|
type = type || "info";
|
|
duration = duration || 8000;
|
|
|
|
var notification = document.createElement("div");
|
|
notification.className =
|
|
"alert alert-" + type + " alert-dismissible fade show position-fixed";
|
|
notification.style.cssText =
|
|
"top: 80px; right: 20px; z-index: 9999; min-width: 300px; max-width: 500px; font-size: 18px; padding: 1.5rem; transition: opacity 0.3s ease-out;";
|
|
notification.innerHTML =
|
|
message +
|
|
'<button type="button" class="btn-close" data-bs-dismiss="alert"></button>';
|
|
|
|
document.body.appendChild(notification);
|
|
|
|
setTimeout(function () {
|
|
notification.classList.remove("show");
|
|
setTimeout(function () {
|
|
if (notification.parentNode) {
|
|
notification.parentNode.removeChild(notification);
|
|
}
|
|
}, 300);
|
|
}, duration);
|
|
},
|
|
|
|
_getLabels: function () {
|
|
// Get current labels from window.groupOrderShop which is updated by checkout_labels.js
|
|
console.log("[_getLabels] Starting label resolution...");
|
|
console.log("[_getLabels] window.groupOrderShop exists:", !!window.groupOrderShop);
|
|
|
|
if (window.groupOrderShop && window.groupOrderShop.labels) {
|
|
console.log("[_getLabels] window.groupOrderShop.labels exists");
|
|
var keysCount = Object.keys(window.groupOrderShop.labels).length;
|
|
console.log("[_getLabels] Keys count:", keysCount);
|
|
if (keysCount > 0) {
|
|
console.log(
|
|
"[_getLabels] ✅ USING window.groupOrderShop.labels (from endpoint):",
|
|
window.groupOrderShop.labels
|
|
);
|
|
return window.groupOrderShop.labels;
|
|
}
|
|
}
|
|
|
|
console.log("[_getLabels] window.groupOrderShop check failed, trying this.labels");
|
|
if (this.labels && Object.keys(this.labels).length > 0) {
|
|
console.log("[_getLabels] ⚠️ USING this.labels (fallback):", this.labels);
|
|
return this.labels;
|
|
}
|
|
|
|
console.log("[_getLabels] ❌ USING default labels");
|
|
return this._getDefaultLabels();
|
|
},
|
|
|
|
_initializeTooltips: function () {
|
|
console.log("[_initializeTooltips] Initializing tooltips with translated labels...");
|
|
var self = this;
|
|
var labels = this._getLabels();
|
|
|
|
// Map of button IDs/classes to label keys
|
|
var tooltipMap = {
|
|
"save-cart-btn": "save_cart",
|
|
"reload-cart-btn": "reload_cart",
|
|
"confirm-order-btn": "save_cart",
|
|
"remove-from-cart": "remove_item",
|
|
};
|
|
|
|
// Map of href patterns to label keys
|
|
var hrefPatterns = [
|
|
{ pattern: /\/checkout$/, labelKey: "proceed_to_checkout" },
|
|
{ pattern: /\/eskaera\/\d+$/, labelKey: "back_to_cart" },
|
|
];
|
|
|
|
// Find all elements with data-bs-toggle="tooltip"
|
|
var tooltipElements = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
|
console.log("[_initializeTooltips] Found", tooltipElements.length, "tooltip elements");
|
|
|
|
// Also update category select placeholder text
|
|
var categorySelect = document.getElementById("realtime-category-select");
|
|
if (categorySelect && categorySelect.options[0]) {
|
|
var allCategoriesLabel =
|
|
labels["browse_categories"] ||
|
|
labels["all_categories"] ||
|
|
"Browse Product Categories";
|
|
categorySelect.options[0].text = allCategoriesLabel;
|
|
console.log(
|
|
"[_initializeTooltips] Updated category select option to:",
|
|
allCategoriesLabel
|
|
);
|
|
}
|
|
|
|
tooltipElements.forEach(function (element) {
|
|
var tooltipText = null;
|
|
var labelKey = null;
|
|
|
|
// Check ID-based mapping
|
|
if (element.id && tooltipMap[element.id]) {
|
|
labelKey = tooltipMap[element.id];
|
|
tooltipText = labels[labelKey];
|
|
}
|
|
|
|
// Check class-based mapping
|
|
if (!tooltipText) {
|
|
for (var key in tooltipMap) {
|
|
if (element.classList.contains(key)) {
|
|
labelKey = tooltipMap[key];
|
|
tooltipText = labels[labelKey];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check href-based mapping
|
|
if (!tooltipText && element.href) {
|
|
for (var i = 0; i < hrefPatterns.length; i++) {
|
|
if (hrefPatterns[i].pattern.test(element.href)) {
|
|
labelKey = hrefPatterns[i].labelKey;
|
|
tooltipText = labels[labelKey];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback: use data-bs-title if no label found
|
|
if (!tooltipText) {
|
|
tooltipText = element.getAttribute("data-bs-title");
|
|
}
|
|
|
|
if (tooltipText) {
|
|
element.setAttribute("title", tooltipText);
|
|
console.log(
|
|
"[_initializeTooltips] Set title on",
|
|
element.id || element.className,
|
|
"→",
|
|
tooltipText,
|
|
"(label key:",
|
|
labelKey,
|
|
")"
|
|
);
|
|
} else {
|
|
console.warn(
|
|
"[_initializeTooltips] No tooltip text found for",
|
|
element.id || element.className
|
|
);
|
|
}
|
|
});
|
|
},
|
|
|
|
_showConfirmation: function (message, onConfirm, onCancel) {
|
|
var self = this;
|
|
// Get current labels - may be updated by checkout_labels.js endpoint
|
|
var labels = this._getLabels();
|
|
console.log("[_showConfirmation] Using labels:", labels);
|
|
|
|
// Create modal backdrop
|
|
var backdrop = document.createElement("div");
|
|
backdrop.className = "modal-backdrop fade show";
|
|
backdrop.style.zIndex = "9998";
|
|
|
|
// Create modal
|
|
var modal = document.createElement("div");
|
|
modal.className = "modal fade show d-block";
|
|
modal.style.zIndex = "9999";
|
|
modal.innerHTML =
|
|
'<div class="modal-dialog modal-dialog-centered">' +
|
|
'<div class="modal-content">' +
|
|
'<div class="modal-header">' +
|
|
'<h5 class="modal-title">' +
|
|
(labels.confirmation || "Confirmation") +
|
|
"</h5>" +
|
|
'<button type="button" class="btn-close" id="modal-close-x"></button>' +
|
|
"</div>" +
|
|
'<div class="modal-body">' +
|
|
"<p>" +
|
|
message.replace(/\n/g, "<br>") +
|
|
"</p>" +
|
|
"</div>" +
|
|
'<div class="modal-footer">' +
|
|
'<button type="button" class="btn btn-secondary" id="modal-cancel">' +
|
|
(labels.cancel || "Cancel") +
|
|
"</button>" +
|
|
'<button type="button" class="btn btn-primary" id="modal-confirm">' +
|
|
(labels.confirm || "Confirm") +
|
|
"</button>" +
|
|
"</div>" +
|
|
"</div>" +
|
|
"</div>";
|
|
|
|
document.body.appendChild(backdrop);
|
|
document.body.appendChild(modal);
|
|
|
|
var closeModal = function () {
|
|
modal.classList.remove("show");
|
|
backdrop.classList.remove("show");
|
|
setTimeout(function () {
|
|
if (modal.parentNode) modal.parentNode.removeChild(modal);
|
|
if (backdrop.parentNode) backdrop.parentNode.removeChild(backdrop);
|
|
}, 150);
|
|
};
|
|
|
|
document.getElementById("modal-confirm").addEventListener("click", function () {
|
|
closeModal();
|
|
if (onConfirm) onConfirm();
|
|
});
|
|
|
|
document.getElementById("modal-cancel").addEventListener("click", function () {
|
|
closeModal();
|
|
if (onCancel) onCancel();
|
|
});
|
|
|
|
document.getElementById("modal-close-x").addEventListener("click", function () {
|
|
closeModal();
|
|
if (onCancel) onCancel();
|
|
});
|
|
},
|
|
|
|
_attachEventListeners: function () {
|
|
var self = this;
|
|
|
|
// Helper function to round decimals correctly
|
|
function roundDecimal(value, decimals) {
|
|
var factor = Math.pow(10, decimals);
|
|
return Math.round(value * factor) / factor;
|
|
}
|
|
|
|
// Safety net: ensure add-to-cart buttons stay enabled in case a stale
|
|
// cached template left the "disabled" attribute or a legacy class.
|
|
// Stock validation happens server-side on confirm; here we keep the UI usable.
|
|
var forceEnableCartButtons = function () {
|
|
var buttons = document.querySelectorAll(".add-to-cart-btn");
|
|
buttons.forEach(function (btn) {
|
|
if (btn.hasAttribute("disabled")) {
|
|
btn.removeAttribute("disabled");
|
|
}
|
|
btn.classList.remove("btn-disabled");
|
|
});
|
|
};
|
|
forceEnableCartButtons();
|
|
|
|
// ============ ATTACH CHECKOUT BUTTONS (ALWAYS, on any page) ============
|
|
// These buttons exist on checkout page, not on cart pages
|
|
if (!this._cartCheckoutListenersAttached) {
|
|
console.log("[_attachEventListeners] Attaching checkout button listeners...");
|
|
|
|
// Button to save as draft (in checkout page)
|
|
var saveBtn = document.getElementById("save-order-btn");
|
|
console.log("[_attachEventListeners] save-order-btn found:", !!saveBtn);
|
|
|
|
if (saveBtn) {
|
|
saveBtn.addEventListener("click", function (e) {
|
|
console.log("[CLICK] save-order-btn clicked");
|
|
e.preventDefault();
|
|
self._saveOrderDraft();
|
|
});
|
|
}
|
|
|
|
// Confirm order button (in checkout page)
|
|
var confirmBtn = document.getElementById("confirm-order-btn");
|
|
console.log("[_attachEventListeners] confirm-order-btn found:", !!confirmBtn);
|
|
|
|
if (confirmBtn) {
|
|
confirmBtn.addEventListener("click", function (e) {
|
|
console.log("[CLICK] confirm-order-btn clicked (save draft)");
|
|
e.preventDefault();
|
|
self._saveOrderDraft();
|
|
});
|
|
}
|
|
|
|
// Button to reload from draft (in My Cart header - cart pages)
|
|
var reloadCartBtn = document.getElementById("reload-cart-btn");
|
|
console.log("[_attachEventListeners] reload-cart-btn found:", !!reloadCartBtn);
|
|
|
|
if (reloadCartBtn) {
|
|
reloadCartBtn.addEventListener("click", function (e) {
|
|
console.log("[CLICK] reload-cart-btn clicked");
|
|
e.preventDefault();
|
|
self._loadDraftCart();
|
|
});
|
|
}
|
|
|
|
// Button to save cart as draft (in My Cart header - shop pages)
|
|
var saveCartBtn = document.getElementById("save-cart-btn");
|
|
console.log("[_attachEventListeners] save-cart-btn found:", !!saveCartBtn);
|
|
|
|
if (saveCartBtn) {
|
|
saveCartBtn.addEventListener("click", function (e) {
|
|
console.log("[CLICK] save-cart-btn clicked");
|
|
e.preventDefault();
|
|
self._saveCartAsDraft();
|
|
});
|
|
}
|
|
|
|
this._cartCheckoutListenersAttached = true;
|
|
console.log("[_attachEventListeners] Checkout listeners attached (one-time)");
|
|
}
|
|
|
|
// ============ LAZY LOADING: Load More Button ============
|
|
this._attachLoadMoreListener();
|
|
|
|
// ============ USE EVENT DELEGATION FOR QUANTITY & CART BUTTONS ============
|
|
// This way, new products loaded via AJAX will automatically have listeners
|
|
var productsGrid = document.getElementById("products-grid");
|
|
|
|
if (!productsGrid) {
|
|
console.log("[_attachEventListeners] No products-grid found (checkout page?)");
|
|
return;
|
|
}
|
|
|
|
// Shared handler for add-to-cart to reuse across grid/document listeners
|
|
var handleAddToCart = function (e) {
|
|
if (e._groupOrderAddToCartHandled) {
|
|
return;
|
|
}
|
|
var cartBtn = e.target.closest(".add-to-cart-btn");
|
|
if (!cartBtn) return;
|
|
|
|
e._groupOrderAddToCartHandled = true;
|
|
|
|
e.preventDefault();
|
|
var form = cartBtn.closest(".add-to-cart-form");
|
|
if (!form) return;
|
|
|
|
var productId = form.getAttribute("data-product-id");
|
|
var productName = form.getAttribute("data-product-name") || "Product";
|
|
var productPrice = parseFloat(form.getAttribute("data-product-price")) || 0;
|
|
var quantityInput = form.querySelector(".product-qty");
|
|
var quantity = quantityInput ? parseFloat(quantityInput.value) : 1;
|
|
|
|
// Block add-to-cart if product is flagged out of stock (from template)
|
|
var isOutOfStock =
|
|
(form.getAttribute("data-out-of-stock") || "false") === "true" ||
|
|
(cartBtn.getAttribute("data-out-of-stock") || "false") === "true";
|
|
|
|
// Fallback guards in case cached markup drops the data attribute
|
|
if (!isOutOfStock) {
|
|
var btnTitle = (cartBtn.getAttribute("title") || "").toLowerCase();
|
|
var btnAria = (cartBtn.getAttribute("aria-label") || "").toLowerCase();
|
|
var iconEl = cartBtn.querySelector("i");
|
|
var hasBanIcon = iconEl && iconEl.classList.contains("fa-ban");
|
|
|
|
if (
|
|
hasBanIcon ||
|
|
btnTitle.includes("out of stock") ||
|
|
btnTitle.includes("sin stock") ||
|
|
btnAria.includes("out of stock") ||
|
|
btnAria.includes("sin stock")
|
|
) {
|
|
isOutOfStock = true;
|
|
}
|
|
}
|
|
if (isOutOfStock) {
|
|
var labels = self._getLabels();
|
|
self._showNotification(
|
|
labels.out_of_stock || "Product is out of stock",
|
|
"warning"
|
|
);
|
|
return;
|
|
}
|
|
|
|
console.log("Adding:", {
|
|
productId: productId,
|
|
productName: productName,
|
|
productPrice: productPrice,
|
|
quantity: quantity,
|
|
});
|
|
|
|
if (quantity > 0) {
|
|
self._addToCart(productId, productName, productPrice, quantity);
|
|
} else {
|
|
var labels2 = self._getLabels();
|
|
self._showNotification(
|
|
labels2.invalid_quantity || "Please enter a valid quantity",
|
|
"warning"
|
|
);
|
|
}
|
|
};
|
|
|
|
// First, adjust quantity steps for all existing inputs
|
|
var unitInputs = document.querySelectorAll(".product-qty");
|
|
console.log("=== ADJUSTING QUANTITY STEPS (from data-quantity-step) ===");
|
|
console.log("Found " + unitInputs.length + " quantity inputs");
|
|
|
|
for (var j = 0; j < unitInputs.length; j++) {
|
|
var form = unitInputs[j].closest(".add-to-cart-form");
|
|
var step = form ? form.getAttribute("data-quantity-step") : null;
|
|
if (!step) step = "1";
|
|
unitInputs[j].step = step;
|
|
unitInputs[j].min = step;
|
|
unitInputs[j].value = "1";
|
|
// Para debug, también marcamos si es unidad o no
|
|
var uomCategory = form ? form.getAttribute("data-uom-category") : "";
|
|
var isUnitCategory = /^unit/i.test(uomCategory) || /^unidad/i.test(uomCategory);
|
|
unitInputs[j].dataset.isUnit = isUnitCategory ? "true" : "false";
|
|
console.log(
|
|
"Input #" +
|
|
j +
|
|
": step=" +
|
|
step +
|
|
', UoM="' +
|
|
uomCategory +
|
|
'", isUnit=' +
|
|
unitInputs[j].dataset.isUnit
|
|
);
|
|
}
|
|
console.log("=== END ADJUSTING QUANTITY STEPS ===");
|
|
|
|
// IMPORTANT: Do NOT clone the grid node - this destroys all products!
|
|
// Instead, use a flag to prevent adding duplicate event listeners
|
|
if (productsGrid._delegationListenersAttached) {
|
|
console.log(
|
|
"[_attachEventListeners] Grid delegation listeners already attached, skipping"
|
|
);
|
|
return;
|
|
}
|
|
productsGrid._delegationListenersAttached = true;
|
|
console.log("[_attachEventListeners] Attaching grid delegation listeners (one-time)");
|
|
|
|
// Quantity decrease button (via event delegation)
|
|
productsGrid.addEventListener("click", function (e) {
|
|
var decreaseBtn = e.target.closest(".qty-decrease");
|
|
if (!decreaseBtn) return;
|
|
|
|
e.preventDefault();
|
|
var productId = decreaseBtn.getAttribute("data-product-id");
|
|
var input = document.getElementById("qty_" + productId);
|
|
if (!input) return;
|
|
|
|
var step = parseFloat(input.step) || 1;
|
|
var currentValue = parseFloat(input.value) || 0;
|
|
var min = parseFloat(input.min) || 0;
|
|
var newValue = Math.max(min, roundDecimal(currentValue - step, 1));
|
|
|
|
// Si es unidad, mostrar como entero
|
|
if (input.dataset.isUnit === "true") {
|
|
input.value = Math.floor(newValue);
|
|
} else {
|
|
input.value = newValue;
|
|
}
|
|
});
|
|
|
|
// Quantity increase button (via event delegation)
|
|
productsGrid.addEventListener("click", function (e) {
|
|
var increaseBtn = e.target.closest(".qty-increase");
|
|
if (!increaseBtn) return;
|
|
|
|
e.preventDefault();
|
|
var productId = increaseBtn.getAttribute("data-product-id");
|
|
var input = document.getElementById("qty_" + productId);
|
|
if (!input) return;
|
|
|
|
var step = parseFloat(input.step) || 1;
|
|
var currentValue = parseFloat(input.value) || 0;
|
|
var newValue = roundDecimal(currentValue + step, 1);
|
|
|
|
// Si es unidad, mostrar como entero
|
|
if (input.dataset.isUnit === "true") {
|
|
input.value = Math.floor(newValue);
|
|
} else {
|
|
input.value = newValue;
|
|
}
|
|
});
|
|
|
|
// Add to cart button (via event delegation on grid)
|
|
productsGrid.addEventListener("click", handleAddToCart);
|
|
|
|
// Also attach a document-level delegation as fallback for dynamically
|
|
// inserted products (infinite scroll) in case the grid listener is lost
|
|
// after DOM replacement.
|
|
if (!this._docCartListenerAttached) {
|
|
document.addEventListener("click", handleAddToCart, true);
|
|
this._docCartListenerAttached = true;
|
|
}
|
|
},
|
|
|
|
_addToCart: function (productId, productName, productPrice, quantity) {
|
|
console.log("_addToCart called with:", {
|
|
productId: productId,
|
|
productName: productName,
|
|
productPrice: productPrice,
|
|
quantity: quantity,
|
|
});
|
|
|
|
if (!this.cart[productId]) {
|
|
this.cart[productId] = {
|
|
name: productName,
|
|
price: productPrice,
|
|
qty: 0,
|
|
};
|
|
}
|
|
this.cart[productId].qty += quantity;
|
|
|
|
console.log("Product added:", productId, this.cart[productId]);
|
|
|
|
this._saveCart();
|
|
this._updateCartDisplay();
|
|
|
|
// Show animation instead of alert
|
|
this._showAddedAnimation(productName);
|
|
|
|
// Use aria-live to announce to screen readers
|
|
var liveRegion = document.getElementById("cart-items-container");
|
|
if (liveRegion) {
|
|
liveRegion.setAttribute("aria-live", "assertive");
|
|
setTimeout(function () {
|
|
liveRegion.setAttribute("aria-live", "polite");
|
|
}, 1000);
|
|
}
|
|
},
|
|
|
|
_showAddedAnimation: function (productName) {
|
|
var self = this;
|
|
// Create toast element
|
|
var toast = document.createElement("div");
|
|
toast.className = "toast-notification";
|
|
|
|
// Get translated "added to cart" label from server
|
|
var labels = this._getLabels();
|
|
var addedMsg = labels.added_to_cart || "added to cart";
|
|
|
|
toast.innerHTML =
|
|
'<i class="fa fa-check"></i> <strong>' + productName + "</strong> " + addedMsg;
|
|
|
|
document.body.appendChild(toast);
|
|
|
|
// Force reflow to activate animation
|
|
toast.offsetHeight;
|
|
toast.classList.add("show");
|
|
|
|
// Remove after 3 seconds
|
|
setTimeout(function () {
|
|
toast.classList.remove("show");
|
|
setTimeout(function () {
|
|
document.body.removeChild(toast);
|
|
}, 300);
|
|
}, 3000);
|
|
},
|
|
|
|
/**
|
|
* Get default translated labels (fallback if JSON fails to parse)
|
|
*/
|
|
_getDefaultLabels: function () {
|
|
return {
|
|
confirmation: "Confirmation",
|
|
cancel: "Cancel",
|
|
confirm: "Confirm",
|
|
empty_cart: "Your cart is empty",
|
|
save_draft_confirm:
|
|
"Are you sure you want to save this cart as draft? Items to save: ",
|
|
save_draft_reload: "You will be able to reload this cart later.",
|
|
error_save_draft: "Error saving cart",
|
|
save_cart: "Save Cart",
|
|
reload_cart: "Reload Cart",
|
|
proceed_to_checkout: "Proceed to Checkout",
|
|
remove_item: "Remove Item",
|
|
confirm_order: "Confirm Order",
|
|
back_to_cart: "Back to Cart",
|
|
all_categories: "All categories",
|
|
// Draft modal labels
|
|
draft_already_exists: "Draft Already Exists",
|
|
draft_exists_message: "A saved draft already exists for the current order period.",
|
|
draft_two_options: "You have two options:",
|
|
draft_option1_title: "Option 1: Merge with Existing Draft",
|
|
draft_option1_desc: "Combine your current cart with the existing draft.",
|
|
draft_existing_items: "Existing draft has",
|
|
draft_current_items: "Current cart has",
|
|
draft_items_count: "item(s)",
|
|
draft_merge_note:
|
|
"Products will be merged by adding quantities. If a product exists in both, quantities will be combined.",
|
|
draft_option2_title: "Option 2: Replace with Current Cart",
|
|
draft_option2_desc: "Delete the old draft and save only the current cart items.",
|
|
draft_replace_warning: "The existing draft will be permanently deleted.",
|
|
draft_merge_btn: "Merge",
|
|
draft_replace_btn: "Replace",
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Update DOM elements with translated labels
|
|
*/
|
|
_updateDOMLabels: function (labels) {
|
|
console.log("[UPDATE_LABELS] Starting DOM update with labels:", labels);
|
|
|
|
// Map of element ID to label key
|
|
var elementLabelMap = {
|
|
"label-home-delivery": "home_delivery",
|
|
"label-delivery-information": "delivery_information",
|
|
"label-important": "important",
|
|
"label-confirm-warning": "confirm_order_warning",
|
|
};
|
|
|
|
// Update each element
|
|
for (var elementId in elementLabelMap) {
|
|
var element = document.getElementById(elementId);
|
|
var labelKey = elementLabelMap[elementId];
|
|
var translatedText = labels[labelKey];
|
|
|
|
console.log(
|
|
"[UPDATE_LABELS] Element:",
|
|
elementId,
|
|
"| Exists:",
|
|
!!element,
|
|
"| Label Key:",
|
|
labelKey,
|
|
"| Translated:",
|
|
translatedText
|
|
);
|
|
|
|
if (element && translatedText) {
|
|
var oldText = element.textContent;
|
|
element.textContent = translatedText;
|
|
console.log(
|
|
"[UPDATE_LABELS] ✅ Updated #" +
|
|
elementId +
|
|
': "' +
|
|
oldText +
|
|
'" → "' +
|
|
translatedText +
|
|
'"'
|
|
);
|
|
} else if (!element) {
|
|
console.log("[UPDATE_LABELS] ❌ Element not found: #" + elementId);
|
|
} else if (!translatedText) {
|
|
console.log(
|
|
"[UPDATE_LABELS] ❌ Label not found: " +
|
|
labelKey +
|
|
" (available keys: " +
|
|
Object.keys(labels).join(", ") +
|
|
")"
|
|
);
|
|
}
|
|
}
|
|
|
|
// Update delivery day text if available
|
|
if (
|
|
window.groupOrderShop &&
|
|
window.groupOrderShop.labels &&
|
|
window.groupOrderShop.labels.delivery_info_template
|
|
) {
|
|
var deliveryDayText = document.getElementById("delivery-day-text");
|
|
console.log("[UPDATE_LABELS] Delivery day text element exists:", !!deliveryDayText);
|
|
|
|
if (deliveryDayText) {
|
|
// Get delivery data from window.deliveryData first, then fallback to attributes
|
|
var pickupDayIndex = "";
|
|
var pickupDate = "";
|
|
var deliveryNotice = "";
|
|
|
|
if (window.deliveryData) {
|
|
console.log(
|
|
"[UPDATE_LABELS] Using window.deliveryData:",
|
|
window.deliveryData
|
|
);
|
|
pickupDayIndex = window.deliveryData.pickupDay || "";
|
|
pickupDate = window.deliveryData.pickupDate || "";
|
|
deliveryNotice = window.deliveryData.deliveryNotice || "";
|
|
} else {
|
|
console.log(
|
|
"[UPDATE_LABELS] window.deliveryData not found, using data attributes"
|
|
);
|
|
var wrap = document.getElementById("wrap");
|
|
pickupDayIndex = wrap ? wrap.getAttribute("data-pickup-day") : "";
|
|
pickupDate = wrap ? wrap.getAttribute("data-pickup-date") : "";
|
|
deliveryNotice = wrap ? wrap.getAttribute("data-delivery-notice") : "";
|
|
}
|
|
|
|
// Normalize: convert "undefined" strings and null to empty for processing
|
|
if (pickupDayIndex === "undefined" || pickupDayIndex === null)
|
|
pickupDayIndex = "";
|
|
if (pickupDate === "undefined" || pickupDate === null) pickupDate = "";
|
|
if (deliveryNotice === "undefined" || deliveryNotice === null)
|
|
deliveryNotice = "";
|
|
|
|
console.log("[UPDATE_LABELS] Delivery data (final):", {
|
|
pickupDayIndex: pickupDayIndex,
|
|
pickupDate: pickupDate,
|
|
deliveryNotice: deliveryNotice,
|
|
});
|
|
|
|
// Day names mapping
|
|
var dayNames = {
|
|
0: "Monday",
|
|
1: "Tuesday",
|
|
2: "Wednesday",
|
|
3: "Thursday",
|
|
4: "Friday",
|
|
5: "Saturday",
|
|
6: "Sunday",
|
|
};
|
|
|
|
// Get translated day names if available
|
|
if (window.groupOrderShop && window.groupOrderShop.day_names) {
|
|
dayNames = window.groupOrderShop.day_names;
|
|
}
|
|
|
|
// Get the day name from index
|
|
var pickupDayName =
|
|
pickupDayIndex && dayNames[pickupDayIndex]
|
|
? dayNames[pickupDayIndex]
|
|
: pickupDayIndex;
|
|
|
|
// Build message from template
|
|
var msg = window.groupOrderShop.labels.delivery_info_template;
|
|
msg = msg.replace("{pickup_day}", pickupDayName);
|
|
msg = msg.replace("{pickup_date}", pickupDate);
|
|
|
|
console.log("[UPDATE_LABELS] Built delivery message:", msg);
|
|
|
|
// Build final HTML output
|
|
var htmlOutput = msg;
|
|
if (deliveryNotice) {
|
|
// Replace newlines with <br> tags for HTML display
|
|
htmlOutput =
|
|
msg.replace(/\n/g, "<br>") +
|
|
"<br><br>" +
|
|
deliveryNotice.replace(/\n/g, "<br>");
|
|
console.log("[UPDATE_LABELS] Final HTML with notice:", htmlOutput);
|
|
} else {
|
|
htmlOutput = msg.replace(/\n/g, "<br>");
|
|
}
|
|
|
|
deliveryDayText.innerHTML = htmlOutput;
|
|
console.log(
|
|
"[UPDATE_LABELS] ✅ Updated delivery day text with translated template"
|
|
);
|
|
}
|
|
} else {
|
|
console.log("[UPDATE_LABELS] ❌ delivery_info_template label not found");
|
|
}
|
|
},
|
|
|
|
_attachLoadMoreListener: function () {
|
|
var self = this;
|
|
var btn = document.getElementById("load-more-btn");
|
|
|
|
if (!btn) {
|
|
console.log("[LAZY_LOADING] No load-more-btn found - lazy loading disabled");
|
|
return;
|
|
}
|
|
|
|
console.log("[LAZY_LOADING] Attaching load-more-btn listener");
|
|
|
|
btn.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
|
|
var orderId = btn.getAttribute("data-order-id");
|
|
var nextPage = btn.getAttribute("data-page");
|
|
var perPage = btn.getAttribute("data-per-page");
|
|
|
|
if (!orderId || !nextPage || !perPage) {
|
|
console.error("[LAZY_LOADING] Missing data attributes", {
|
|
orderId: orderId,
|
|
nextPage: nextPage,
|
|
perPage: perPage,
|
|
});
|
|
return;
|
|
}
|
|
|
|
console.log("[LAZY_LOADING] Loading page", nextPage, "for order", orderId);
|
|
|
|
// Show spinner: disable button and change text
|
|
var originalText = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<i class="fa fa-spinner fa-spin me-2"></i>Loading...';
|
|
|
|
// AJAX GET request
|
|
var xhr = new XMLHttpRequest();
|
|
var url = "/eskaera/" + orderId + "/load-page?page=" + nextPage;
|
|
|
|
xhr.open("GET", url, true);
|
|
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
|
|
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
console.log("[LAZY_LOADING] Page loaded successfully");
|
|
|
|
// Parse response HTML
|
|
var html = xhr.responseText;
|
|
var grid = document.getElementById("products-grid");
|
|
|
|
if (!grid) {
|
|
console.error("[LAZY_LOADING] products-grid not found");
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalText;
|
|
return;
|
|
}
|
|
|
|
// Insert new products at the end of grid
|
|
grid.insertAdjacentHTML("beforeend", html);
|
|
console.log("[LAZY_LOADING] Products inserted into grid");
|
|
|
|
// Re-attach event listeners for new products
|
|
self._attachEventListeners();
|
|
console.log("[LAZY_LOADING] Event listeners re-attached");
|
|
|
|
// Update button state
|
|
var nextPageNum = parseInt(nextPage) + 1;
|
|
|
|
// Check if there are more products by looking at the response
|
|
// If response contains data-next="false" or similar, hide button
|
|
// For now, we'll always increment and let backend handle has_next
|
|
btn.setAttribute("data-page", nextPageNum);
|
|
|
|
// Hide button if no more pages (check if response indicates no more)
|
|
// Simple approach: if response is very short, assume no more products
|
|
if (html.trim().length < 100) {
|
|
console.log("[LAZY_LOADING] No more products, hiding load-more button");
|
|
btn.style.display = "none";
|
|
} else {
|
|
// Re-enable button for next page
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalText;
|
|
}
|
|
} else {
|
|
console.error("[LAZY_LOADING] Error loading page:", xhr.status);
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalText;
|
|
var errorMsg = "Error loading more products (status: " + xhr.status + ")";
|
|
if (self._showNotification) {
|
|
self._showNotification(errorMsg, "danger");
|
|
} else {
|
|
alert(errorMsg);
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
console.error("[LAZY_LOADING] Network error");
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalText;
|
|
var errorMsg = "Error: Network request failed";
|
|
if (self._showNotification) {
|
|
self._showNotification(errorMsg, "danger");
|
|
} else {
|
|
alert(errorMsg);
|
|
}
|
|
};
|
|
|
|
xhr.send();
|
|
});
|
|
},
|
|
|
|
_updateCartDisplay: function () {
|
|
var cartContainer = document.getElementById("cart-items-container");
|
|
if (!cartContainer) return;
|
|
|
|
// Get labels first before using them
|
|
var labels = this._getLabels();
|
|
|
|
if (Object.keys(this.cart).length === 0) {
|
|
cartContainer.innerHTML =
|
|
'<p class="text-muted" style="font-size: 1.1rem;">' +
|
|
(labels.empty_cart || "This order's cart is empty.") +
|
|
"</p>";
|
|
return;
|
|
}
|
|
|
|
var html = '<div class="list-group">';
|
|
var total = 0;
|
|
var self = this;
|
|
var removeItemLabel = labels.remove_item || "Remove Item";
|
|
|
|
Object.keys(this.cart).forEach(function (productId) {
|
|
var item = self.cart[productId];
|
|
var subtotal = item.qty * item.price;
|
|
total += subtotal;
|
|
|
|
html +=
|
|
'<div class="list-group-item" style="font-size: 1.05rem;">' +
|
|
'<div class="mb-2">' +
|
|
'<h6 class="mb-0" style="font-size: 1.1rem;">' +
|
|
self.escapeHtml(item.name) +
|
|
"</h6>" +
|
|
"</div>" +
|
|
'<div class="d-flex justify-content-between align-items-center">' +
|
|
'<small class="text-muted" style="font-size: 1rem;">' +
|
|
parseFloat(item.qty).toFixed(1) +
|
|
" x €" +
|
|
item.price.toFixed(2) +
|
|
"</small>" +
|
|
'<div class="d-flex align-items-center gap-2">' +
|
|
'<strong style="font-size: 1.1rem;">€' +
|
|
subtotal.toFixed(2) +
|
|
"</strong>" +
|
|
'<button class="btn btn-sm btn-danger remove-from-cart" ' +
|
|
'data-product-id="' +
|
|
productId +
|
|
'" aria-label="Remove ' +
|
|
self.escapeHtml(item.name) +
|
|
' from cart" data-bs-toggle="tooltip" title="' +
|
|
removeItemLabel +
|
|
'">' +
|
|
'<i class="fa fa-trash" aria-hidden="true"></i>' +
|
|
"</button>" +
|
|
"</div>" +
|
|
"</div>" +
|
|
"</div>";
|
|
});
|
|
|
|
html += "</div>";
|
|
html +=
|
|
'<div class="cart-total mt-3 pt-3" style="font-size: 1.2rem; font-weight: bold;">' +
|
|
"Total: €" +
|
|
total.toFixed(2) +
|
|
"</div>";
|
|
|
|
cartContainer.innerHTML = html;
|
|
|
|
// Reassign event listeners to remove buttons
|
|
var removeButtons = cartContainer.querySelectorAll(".remove-from-cart");
|
|
for (var i = 0; i < removeButtons.length; i++) {
|
|
removeButtons[i].addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
var productId = this.getAttribute("data-product-id");
|
|
self._removeFromCart(productId);
|
|
});
|
|
}
|
|
|
|
// Reinitialize tooltips for newly added remove buttons
|
|
console.log("[_updateCartDisplay] Reinitializing tooltips for remove buttons");
|
|
var tooltipsToInit = cartContainer.querySelectorAll('[data-bs-toggle="tooltip"]');
|
|
tooltipsToInit.forEach(function (elem) {
|
|
var bsTooltip = window.bootstrap?.Tooltip;
|
|
if (bsTooltip) {
|
|
// Destroy existing tooltip if any
|
|
var existingTooltip = bsTooltip.getInstance(elem);
|
|
if (existingTooltip) {
|
|
existingTooltip.dispose();
|
|
}
|
|
// Create new tooltip with updated title
|
|
new bsTooltip(elem);
|
|
console.log(
|
|
"[_updateCartDisplay] Tooltip reinitialized for element:",
|
|
elem.getAttribute("title")
|
|
);
|
|
}
|
|
});
|
|
},
|
|
|
|
_removeFromCart: function (productId) {
|
|
console.log("Removing from cart:", productId);
|
|
var removedItem = this.cart[productId];
|
|
var itemName = removedItem ? removedItem.name : "Product";
|
|
|
|
delete this.cart[productId];
|
|
this._saveCart();
|
|
|
|
// Use aria-live to announce to screen readers
|
|
var liveRegion = document.getElementById("cart-items-container");
|
|
if (liveRegion) {
|
|
liveRegion.setAttribute("aria-live", "assertive");
|
|
setTimeout(function () {
|
|
liveRegion.setAttribute("aria-live", "polite");
|
|
}, 1000);
|
|
}
|
|
|
|
this._updateCartDisplay();
|
|
},
|
|
|
|
_saveCartAsDraft: function () {
|
|
console.log("Saving cart as draft");
|
|
|
|
var self = this;
|
|
var items = [];
|
|
|
|
Object.keys(this.cart).forEach(function (productId) {
|
|
var item = self.cart[productId];
|
|
items.push({
|
|
product_id: productId,
|
|
product_name: item.name,
|
|
quantity: item.qty,
|
|
product_price: item.price,
|
|
});
|
|
});
|
|
|
|
if (items.length === 0) {
|
|
var labels = self._getLabels();
|
|
self._showNotification(labels.empty_cart || "Your cart is empty", "warning");
|
|
return;
|
|
}
|
|
|
|
// Call save-order endpoint which handles draft conflicts
|
|
self._executeSaveCartAsDraft(items);
|
|
},
|
|
|
|
_executeSaveCartAsDraft: function (items) {
|
|
var self = this;
|
|
|
|
var orderData = {
|
|
order_id: this.orderId,
|
|
items: items,
|
|
merge_action: "replace",
|
|
};
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("POST", "/eskaera/save-order", true);
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
try {
|
|
var data = JSON.parse(xhr.responseText);
|
|
var labels = self._getLabels();
|
|
|
|
if (data.success) {
|
|
var successMsg =
|
|
(labels.draft_saved_success || "Cart saved as draft successfully") +
|
|
" (Order ID: " +
|
|
data.sale_order_id +
|
|
")";
|
|
self._showNotification("✓ " + successMsg, "success", 5000);
|
|
} else {
|
|
self._showNotification(
|
|
"Error: " + (data.error || labels.error_unknown || "Unknown error"),
|
|
"danger"
|
|
);
|
|
}
|
|
} catch (e) {
|
|
console.error("Error parsing response:", e);
|
|
var labels = self._getLabels();
|
|
self._showNotification(
|
|
labels.error_processing_response || "Error processing response",
|
|
"danger"
|
|
);
|
|
}
|
|
} else {
|
|
if (self._isClosedOrderResponse(xhr)) {
|
|
self._clearCurrentOrderCartSilently();
|
|
self._updateCartDisplay();
|
|
return;
|
|
}
|
|
try {
|
|
var errorData = JSON.parse(xhr.responseText);
|
|
self._showNotification(
|
|
"Error " + xhr.status + ": " + (errorData.error || "Request error"),
|
|
"danger"
|
|
);
|
|
} catch (e) {
|
|
var labels = self._getLabels();
|
|
self._showNotification(
|
|
labels.error_saving_draft ||
|
|
"Error saving cart (HTTP " + xhr.status + ")",
|
|
"danger"
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
console.error("Error:", xhr);
|
|
var labels = self._getLabels();
|
|
self._showNotification(labels.connection_error || "Connection error", "danger");
|
|
};
|
|
|
|
xhr.send(JSON.stringify(orderData));
|
|
},
|
|
|
|
_loadDraftCart: function () {
|
|
console.log("Loading draft cart (manual)");
|
|
|
|
var self = this;
|
|
|
|
// Check if cart has items
|
|
var hasItems = Object.keys(this.cart).length > 0;
|
|
|
|
if (hasItems) {
|
|
// Ask for confirmation if cart has items
|
|
var labels = this._getLabels();
|
|
var confirmMessage =
|
|
(labels.reload_draft_confirm ||
|
|
"Are you sure you want to load your last saved draft?") +
|
|
"\n\n" +
|
|
(labels.reload_draft_replace || "This will replace your current cart items") +
|
|
" (" +
|
|
Object.keys(this.cart).length +
|
|
" " +
|
|
(labels.items_placeholder || "items") +
|
|
") " +
|
|
(labels.reload_draft_with || "with the saved draft.");
|
|
|
|
self._showConfirmation(confirmMessage, function () {
|
|
// User confirmed - continue with load
|
|
self._executeLoadDraftCart();
|
|
});
|
|
} else {
|
|
// Cart is empty, load directly without confirmation
|
|
self._executeLoadDraftCart();
|
|
}
|
|
},
|
|
|
|
_executeLoadDraftCart: function () {
|
|
var self = this;
|
|
|
|
var orderData = {
|
|
order_id: this.orderId,
|
|
};
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("POST", "/eskaera/load-draft", true);
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
try {
|
|
var data = JSON.parse(xhr.responseText);
|
|
if (data.success) {
|
|
// Clear current cart
|
|
self.cart = {};
|
|
|
|
// Load items from draft order
|
|
var items = data.items || [];
|
|
items.forEach(function (item) {
|
|
var productId = item.product_id;
|
|
self.cart[productId] = {
|
|
name: item.product_name,
|
|
price: item.product_price,
|
|
qty: item.quantity,
|
|
};
|
|
});
|
|
|
|
// Save to localStorage
|
|
self._saveCart();
|
|
|
|
// Update display
|
|
self._updateCartDisplay();
|
|
|
|
var labels = self._getLabels();
|
|
var loadMsg =
|
|
(labels.draft_loaded_success || "Loaded") +
|
|
" " +
|
|
items.length +
|
|
" items from draft order (ID: " +
|
|
data.sale_order_id +
|
|
")";
|
|
self._showNotification("✓ " + loadMsg, "success", 5000);
|
|
} else {
|
|
self._showNotification(
|
|
"Error: " + (data.error || labels.error_unknown || "Unknown error"),
|
|
"danger"
|
|
);
|
|
}
|
|
} catch (e) {
|
|
console.error("Error parsing response:", e);
|
|
var labels = self._getLabels();
|
|
self._showNotification(
|
|
labels.error_processing_response || "Error processing response",
|
|
"danger"
|
|
);
|
|
}
|
|
} else {
|
|
if (self._isClosedOrderResponse(xhr)) {
|
|
self._clearCurrentOrderCartSilently();
|
|
self._updateCartDisplay();
|
|
return;
|
|
}
|
|
try {
|
|
var errorData = JSON.parse(xhr.responseText);
|
|
self._showNotification(
|
|
"Error " + xhr.status + ": " + (errorData.error || "Request error"),
|
|
"danger"
|
|
);
|
|
} catch (e) {
|
|
var labels = self._getLabels();
|
|
self._showNotification(
|
|
labels.error_loading_draft ||
|
|
"Error loading draft (HTTP " + xhr.status + ")",
|
|
"danger"
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
console.error("Error:", xhr);
|
|
var labels = self._getLabels();
|
|
self._showNotification(labels.connection_error || "Connection error", "danger");
|
|
};
|
|
|
|
xhr.send(JSON.stringify(orderData));
|
|
},
|
|
|
|
_saveOrderDraft: function () {
|
|
console.log("[_saveOrderDraft] Starting - this.orderId:", this.orderId);
|
|
|
|
var self = this;
|
|
var labels = this._getLabels();
|
|
var cartKey = "eskaera_" + this.orderId + "_cart";
|
|
var storedCart = localStorage.getItem(cartKey);
|
|
var cart = storedCart ? JSON.parse(storedCart) : this.cart;
|
|
var items = [];
|
|
|
|
Object.keys(cart).forEach(function (productId) {
|
|
var item = cart[productId];
|
|
items.push({
|
|
product_id: productId,
|
|
product_name: item.name,
|
|
quantity: item.qty,
|
|
product_price: item.price,
|
|
});
|
|
});
|
|
|
|
var orderData = {
|
|
order_id: this.orderId,
|
|
items: items,
|
|
};
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("POST", "/eskaera/save-order", true);
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
try {
|
|
var data = JSON.parse(xhr.responseText);
|
|
console.log("Response:", data);
|
|
|
|
if (data.success) {
|
|
var successMsg =
|
|
labels.draft_saved_success ||
|
|
labels.draft_saved ||
|
|
"Order saved as draft successfully";
|
|
self._showNotification("\u2713 " + successMsg, "success", 5000);
|
|
} else {
|
|
self._showNotification(
|
|
"Error: " + (data.error || labels.error_unknown || "Unknown error"),
|
|
"danger"
|
|
);
|
|
}
|
|
} catch (e) {
|
|
console.error("Error parsing response:", e);
|
|
self._showNotification("Error processing response", "danger");
|
|
}
|
|
} else {
|
|
if (self._isClosedOrderResponse(xhr)) {
|
|
self._clearCurrentOrderCartSilently();
|
|
self._updateCartDisplay();
|
|
return;
|
|
}
|
|
try {
|
|
var errorData = JSON.parse(xhr.responseText);
|
|
console.error("HTTP error:", xhr.status, errorData);
|
|
self._showNotification(
|
|
"Error " + xhr.status + ": " + (errorData.error || "Request error"),
|
|
"danger"
|
|
);
|
|
} catch (e) {
|
|
console.error("HTTP error:", xhr.status, xhr.responseText);
|
|
self._showNotification(
|
|
"Error saving order (HTTP " + xhr.status + ")",
|
|
"danger"
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
console.error("Error:", xhr);
|
|
var labels = self._getLabels();
|
|
self._showNotification(labels.connection_error || "Connection error", "danger");
|
|
};
|
|
|
|
xhr.send(JSON.stringify(orderData));
|
|
},
|
|
|
|
_confirmOrder: function () {
|
|
console.log("=== _confirmOrder started ===");
|
|
console.log("orderId:", this.orderId);
|
|
|
|
// IMPORTANT: Read cart directly from localStorage, not from this.cart
|
|
// because home_delivery.js updates localStorage directly
|
|
var cartKey = "eskaera_" + this.orderId + "_cart";
|
|
var storedCart = localStorage.getItem(cartKey);
|
|
console.log("localStorage[" + cartKey + "]:", storedCart);
|
|
|
|
// Parse cart from localStorage (more reliable than this.cart)
|
|
var cart = storedCart ? JSON.parse(storedCart) : this.cart;
|
|
console.log("Parsed cart from localStorage:", cart);
|
|
|
|
var self = this;
|
|
var items = [];
|
|
|
|
Object.keys(cart).forEach(function (productId) {
|
|
var item = cart[productId];
|
|
console.log("Processing cart item: productId=" + productId + ", item=", item);
|
|
items.push({
|
|
product_id: productId,
|
|
product_name: item.name,
|
|
quantity: item.qty,
|
|
unit_price: item.price,
|
|
});
|
|
});
|
|
|
|
console.log("Items to send to server:", items);
|
|
console.log("Total items count:", items.length);
|
|
|
|
// Check if home delivery is enabled
|
|
var deliveryCheckbox = document.getElementById("home-delivery-checkbox");
|
|
var isDelivery = deliveryCheckbox ? deliveryCheckbox.checked : false;
|
|
|
|
var orderData = {
|
|
order_id: this.orderId,
|
|
items: items,
|
|
is_delivery: isDelivery,
|
|
};
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("POST", "/eskaera/confirm", true);
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
console.log("Sending request to /eskaera/confirm with data:", orderData);
|
|
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
try {
|
|
var data = JSON.parse(xhr.responseText);
|
|
console.log("Response:", data);
|
|
var labels = self._getLabels();
|
|
if (data.success) {
|
|
var message =
|
|
data.message || labels.order_confirmed || "Order confirmed";
|
|
self._showNotification("✓ " + message, "success", 4000);
|
|
// Clear cart from localStorage
|
|
localStorage.removeItem("eskaera_" + self.orderId + "_cart");
|
|
console.log("Cart cleared from localStorage after confirmation");
|
|
// Save confirmation message in sessionStorage to display on eskaera page
|
|
sessionStorage.setItem("confirmation_message", message);
|
|
// Wait a moment before redirecting to let user see the message
|
|
setTimeout(function () {
|
|
window.location.href = data.redirect_url || "/eskaera";
|
|
}, 4000);
|
|
} else {
|
|
var unknownErrorMsg =
|
|
labels.error_unknown || labels.error_unknown || "Unknown error";
|
|
self._showNotification(
|
|
"Error: " + (data.error || unknownErrorMsg),
|
|
"danger"
|
|
);
|
|
}
|
|
} catch (e) {
|
|
console.error("Error parsing response:", e);
|
|
var labels = self._getLabels();
|
|
self._showNotification(
|
|
labels.error_processing_response || "Error processing response",
|
|
"danger"
|
|
);
|
|
}
|
|
} else {
|
|
if (self._isClosedOrderResponse(xhr)) {
|
|
self._clearCurrentOrderCartSilently();
|
|
self._updateCartDisplay();
|
|
return;
|
|
}
|
|
try {
|
|
var errorData = JSON.parse(xhr.responseText);
|
|
console.error("HTTP error:", xhr.status, errorData);
|
|
self._showNotification(
|
|
"Error " + xhr.status + ": " + (errorData.error || "Request error"),
|
|
"danger"
|
|
);
|
|
} catch (e) {
|
|
console.error("HTTP error:", xhr.status, xhr.responseText);
|
|
self._showNotification(
|
|
"Error confirming order (HTTP " + xhr.status + ")",
|
|
"danger"
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
console.error("Error:", xhr);
|
|
var labels = self._getLabels();
|
|
self._showNotification(labels.connection_error || "Connection error", "danger");
|
|
};
|
|
|
|
xhr.send(JSON.stringify(orderData));
|
|
},
|
|
|
|
escapeHtml: function (text) {
|
|
var div = document.createElement("div");
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
},
|
|
};
|
|
|
|
// Initialize when DOM is ready
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
console.log("DOM loaded");
|
|
console.log("Looking for #cart-items-container...");
|
|
console.log("Looking for #confirm-order-btn...");
|
|
|
|
var cartContainer = document.getElementById("cart-items-container");
|
|
var confirmBtn = document.getElementById("confirm-order-btn");
|
|
|
|
console.log("cart-items-container found:", !!cartContainer);
|
|
console.log("confirm-order-btn found:", !!confirmBtn);
|
|
|
|
// Always initialize - it handles both cart pages and checkout pages
|
|
console.log("Calling init()");
|
|
var result = window.groupOrderShop.init();
|
|
console.log("init() result:", result);
|
|
});
|
|
|
|
// Handle confirm order buttons in portal (My Orders page)
|
|
document.addEventListener("click", function (e) {
|
|
if (e.target.closest(".confirm-order-btn")) {
|
|
e.preventDefault();
|
|
var btn = e.target.closest(".confirm-order-btn");
|
|
var groupOrderId = btn.getAttribute("data-group-order-id");
|
|
var orderId = btn.getAttribute("data-order-id");
|
|
|
|
console.log("Confirm order clicked: order=" + orderId + ", group=" + groupOrderId);
|
|
|
|
if (!groupOrderId || !orderId) {
|
|
if (window.groupOrderShop && window.groupOrderShop._showNotification) {
|
|
window.groupOrderShop._showNotification(
|
|
"Error: Missing order or group information",
|
|
"danger"
|
|
);
|
|
} else {
|
|
alert("Error: Missing order or group information");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Show loading state
|
|
var originalText = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
|
|
|
|
// Send AJAX request to confirm the order
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("POST", "/eskaera/" + groupOrderId + "/confirm/" + orderId, true);
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
xhr.onload = function () {
|
|
btn.disabled = false;
|
|
|
|
if (xhr.status === 200) {
|
|
try {
|
|
var response;
|
|
if (
|
|
typeof xhr.responseText === "string" &&
|
|
xhr.responseText.trim() !== ""
|
|
) {
|
|
response = JSON.parse(xhr.responseText);
|
|
} else {
|
|
response = {};
|
|
}
|
|
|
|
console.log("Response from confirm endpoint:", response);
|
|
|
|
// Odoo JSON-RPC wraps the result in response.result
|
|
var result = response.result || response;
|
|
|
|
if (result && result.success) {
|
|
console.log(
|
|
"Order confirmed successfully: order_id=" + result.order_id
|
|
);
|
|
btn.innerHTML = '<i class="fa fa-check"></i>';
|
|
btn.classList.remove("btn-success");
|
|
btn.classList.add("btn-secondary");
|
|
btn.disabled = true;
|
|
btn.title = "Order confirmed";
|
|
|
|
// Show success notification with order_id
|
|
var message = "Order #" + result.order_id + " confirmed successfully";
|
|
if (result.message) {
|
|
message = result.message + " (Order #" + result.order_id + ")";
|
|
}
|
|
|
|
if (window.groupOrderShop && window.groupOrderShop._showNotification) {
|
|
window.groupOrderShop._showNotification(message, "success", 4000);
|
|
} else {
|
|
alert(message);
|
|
}
|
|
} else {
|
|
console.error("Error confirming order:", result);
|
|
btn.innerHTML = originalText;
|
|
var errorMsg =
|
|
"Error: " +
|
|
(result && result.error
|
|
? result.error
|
|
: labels.error_unknown || "Unknown error");
|
|
if (window.groupOrderShop && window.groupOrderShop._showNotification) {
|
|
window.groupOrderShop._showNotification(errorMsg, "danger");
|
|
} else {
|
|
alert(errorMsg);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error("Error parsing response:", e);
|
|
console.error("Response text was:", xhr.responseText);
|
|
btn.innerHTML = originalText;
|
|
var errorMsg = "Error processing response: " + e.message;
|
|
if (window.groupOrderShop && window.groupOrderShop._showNotification) {
|
|
window.groupOrderShop._showNotification(errorMsg, "danger");
|
|
} else {
|
|
alert(errorMsg);
|
|
}
|
|
}
|
|
} else {
|
|
console.error("HTTP error:", xhr.status, xhr.responseText);
|
|
btn.innerHTML = originalText;
|
|
var errorMsg = "Error " + xhr.status + ": Failed to confirm order";
|
|
if (window.groupOrderShop && window.groupOrderShop._showNotification) {
|
|
window.groupOrderShop._showNotification(errorMsg, "danger");
|
|
} else {
|
|
alert(errorMsg);
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function () {
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalText;
|
|
var errorMsg = "Error: Network request failed";
|
|
if (window.groupOrderShop && window.groupOrderShop._showNotification) {
|
|
window.groupOrderShop._showNotification(errorMsg, "danger");
|
|
} else {
|
|
alert(errorMsg);
|
|
}
|
|
};
|
|
|
|
xhr.send(JSON.stringify({}));
|
|
}
|
|
});
|
|
|
|
// Also try to initialize after a delay in case DOM
|
|
// takes longer to load
|
|
setTimeout(function () {
|
|
if (!window.groupOrderShop.orderId) {
|
|
console.log("Reintentando init() después de delay...");
|
|
var cartContainer = document.getElementById("cart-items-container");
|
|
var confirmBtn = document.getElementById("confirm-order-btn");
|
|
|
|
if (cartContainer || confirmBtn) {
|
|
console.log("Llamando a init() en delay");
|
|
var result = window.groupOrderShop.init();
|
|
console.log("init() en delay resultado:", result);
|
|
}
|
|
}
|
|
}, 1000);
|
|
})();
|