mirror of
https://git.kh3group.com/georgebiri/khy_website.git
synced 2026-07-02 07:03:33 +00:00
feat: enhance product comparison functionality with Add To Quote integration and initialization checks
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
6c817cbd20
commit
be36d6aa3c
1 changed files with 193 additions and 12 deletions
205
scripts/main.js
205
scripts/main.js
|
|
@ -1054,6 +1054,13 @@ function initSite() {
|
|||
function initProductComparison() {
|
||||
console.log("=== INITIALIZING PRODUCT COMPARISON ===");
|
||||
|
||||
// Prevent running twice (it's invoked in multiple places)
|
||||
if (window.__cmpInitialized) {
|
||||
console.log("[Comparison] Already initialized, skipping");
|
||||
return;
|
||||
}
|
||||
window.__cmpInitialized = true;
|
||||
|
||||
// Get product IDs from URL parameters
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const product1Id = urlParams.get("product1");
|
||||
|
|
@ -1061,6 +1068,10 @@ function initProductComparison() {
|
|||
|
||||
console.log("URL Parameters:", { product1Id, product2Id });
|
||||
|
||||
// Keep references to the two products for event handlers
|
||||
let cmpProduct1 = null;
|
||||
let cmpProduct2 = null;
|
||||
|
||||
// Fetch product data
|
||||
fetch("data/products.json")
|
||||
.then((response) => {
|
||||
|
|
@ -1080,12 +1091,14 @@ function initProductComparison() {
|
|||
// Update product cards
|
||||
if (product1) {
|
||||
console.log("Updating product card 1 with:", product1.name);
|
||||
cmpProduct1 = product1;
|
||||
updateProductCard(1, product1);
|
||||
updateComparisonTable(product1, 1);
|
||||
}
|
||||
|
||||
if (product2) {
|
||||
console.log("Updating product card 2 with:", product2.name);
|
||||
cmpProduct2 = product2;
|
||||
updateProductCard(2, product2);
|
||||
updateComparisonTable(product2, 2);
|
||||
}
|
||||
|
|
@ -1095,12 +1108,113 @@ function initProductComparison() {
|
|||
|
||||
// Update View More link with current comparison state
|
||||
updateViewMoreLink(product1Id, product2Id);
|
||||
|
||||
// Wire Add To Quote buttons (first -> product1, second -> product2)
|
||||
wireComparisonAddToQuote(cmpProduct1, cmpProduct2);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error loading products:", error);
|
||||
});
|
||||
}
|
||||
|
||||
// Bind the two Add To Quote buttons on the comparison page
|
||||
function wireComparisonAddToQuote(prod1, prod2) {
|
||||
try {
|
||||
const addButtons = Array.from(document.querySelectorAll("button")).filter(
|
||||
(b) => (b.textContent || "").trim() === "Add To Quote"
|
||||
);
|
||||
|
||||
if (addButtons.length === 0) {
|
||||
console.log("[Comparison] No Add To Quote buttons found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure deterministic order: the first encountered is for product 1
|
||||
const btn1 = addButtons[0] || null;
|
||||
const btn2 = addButtons[1] || null;
|
||||
|
||||
function toQuotePayload(p) {
|
||||
if (!p) return null;
|
||||
return {
|
||||
id: Number(p.id),
|
||||
name: p.name || "Product",
|
||||
image: p.image || "",
|
||||
color:
|
||||
(p.colors &&
|
||||
p.colors[0] &&
|
||||
(p.colors[0].name || p.colors[0].value)) ||
|
||||
"Default",
|
||||
size: (p.sizes && p.sizes[0]) || "Standard",
|
||||
quantity: 1,
|
||||
};
|
||||
}
|
||||
|
||||
if (btn1) {
|
||||
btn1.type = btn1.getAttribute("type") || "button";
|
||||
btn1.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const payload = toQuotePayload(prod1);
|
||||
if (!payload) return;
|
||||
payload.quantity = 1; // force 1 for comparison adds
|
||||
if (typeof addToQuote === "function") {
|
||||
addToQuote(payload);
|
||||
} else {
|
||||
addToQuoteFallback(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btn2) {
|
||||
btn2.type = btn2.getAttribute("type") || "button";
|
||||
btn2.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const payload = toQuotePayload(prod2);
|
||||
if (!payload) return;
|
||||
payload.quantity = 1; // force 1 for comparison adds
|
||||
if (typeof addToQuote === "function") {
|
||||
addToQuote(payload);
|
||||
} else {
|
||||
addToQuoteFallback(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Delegated fallback (in case DOM changes after load)
|
||||
document.addEventListener("click", (e) => {
|
||||
const t = e.target.closest && e.target.closest("button");
|
||||
if (!t) return;
|
||||
const label = (t.textContent || "").trim();
|
||||
if (label !== "Add To Quote") return;
|
||||
// Determine which button index this is relative to current NodeList
|
||||
const currentButtons = Array.from(
|
||||
document.querySelectorAll("button")
|
||||
).filter((b) => (b.textContent || "").trim() === "Add To Quote");
|
||||
const idx = currentButtons.indexOf(t);
|
||||
if (idx === 0) {
|
||||
const payload = toQuotePayload(prod1);
|
||||
if (payload) {
|
||||
payload.quantity = 1;
|
||||
(typeof addToQuote === "function" ? addToQuote : addToQuoteFallback)(
|
||||
payload
|
||||
);
|
||||
}
|
||||
} else if (idx === 1) {
|
||||
const payload = toQuotePayload(prod2);
|
||||
if (payload) {
|
||||
payload.quantity = 1;
|
||||
(typeof addToQuote === "function" ? addToQuote : addToQuoteFallback)(
|
||||
payload
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[Comparison] Failed to wire Add To Quote buttons:", err);
|
||||
}
|
||||
}
|
||||
|
||||
function updateProductCard(slotNumber, product) {
|
||||
console.log(`=== UPDATING PRODUCT CARD ${slotNumber} ===`);
|
||||
console.log("Product data:", product);
|
||||
|
|
@ -1537,20 +1651,59 @@ function initQuoteBadge() {
|
|||
function initAddToQuote() {
|
||||
const addToQuoteBtn = document.getElementById("add-to-quote-btn");
|
||||
if (addToQuoteBtn) {
|
||||
addToQuoteBtn.addEventListener("click", function () {
|
||||
// Get product data from the page
|
||||
try {
|
||||
// Ensure button is not treated as a submit in case inside a form
|
||||
if (!addToQuoteBtn.getAttribute("type")) {
|
||||
addToQuoteBtn.setAttribute("type", "button");
|
||||
}
|
||||
|
||||
addToQuoteBtn.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log("[AddToQuote] Direct click captured");
|
||||
|
||||
const productData = getProductDataFromPage();
|
||||
console.log("[AddToQuote] productData:", productData);
|
||||
if (productData) {
|
||||
if (typeof addToQuote === "function") {
|
||||
addToQuote(productData);
|
||||
} else {
|
||||
addToQuoteFallback(productData);
|
||||
}
|
||||
} else {
|
||||
console.warn(
|
||||
"[AddToQuote] No product data found. Check URL id and DOM."
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[AddToQuote] Failed to bind direct listener:", err);
|
||||
}
|
||||
}
|
||||
|
||||
// Delegated fallback in case the button is replaced dynamically
|
||||
document.addEventListener("click", function (e) {
|
||||
const btn = e.target.closest && e.target.closest("#add-to-quote-btn");
|
||||
if (!btn) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log("[AddToQuote] Delegated click captured");
|
||||
try {
|
||||
const productData = getProductDataFromPage();
|
||||
console.log("[AddToQuote][delegated] productData:", productData);
|
||||
if (productData) {
|
||||
// Add to quote using the global function
|
||||
if (typeof addToQuote === "function") {
|
||||
addToQuote(productData);
|
||||
} else {
|
||||
// Fallback: directly use localStorage
|
||||
addToQuoteFallback(productData);
|
||||
}
|
||||
} else {
|
||||
console.warn("[AddToQuote][delegated] No product data found.");
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("[AddToQuote][delegated] Error handling click:", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Get product data from the current page
|
||||
|
|
@ -1569,12 +1722,40 @@ function getProductDataFromPage() {
|
|||
const selectedSize = getSelectedSize();
|
||||
const selectedQuantity = getSelectedQuantity();
|
||||
|
||||
// Get product name and image (you might need to adjust these selectors)
|
||||
const productName = document.querySelector("h1")?.textContent || "Product";
|
||||
const productImage =
|
||||
document.querySelector(".w-\\[500px\\].h-\\[500px\\] img")?.src ||
|
||||
document.querySelector(".w-[500px].h-[500px] img")?.src ||
|
||||
"";
|
||||
// Get product name and a best-effort product image
|
||||
const productName =
|
||||
document.querySelector("h1")?.textContent?.trim() || "Product";
|
||||
let productImage = "";
|
||||
|
||||
// Helper to guard against invalid selectors (e.g., unescaped brackets)
|
||||
function qsSafe(selector) {
|
||||
try {
|
||||
return document.querySelector(selector);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Try a series of selectors safely
|
||||
const imageCandidates = [
|
||||
".w-\\[500px\\].h-\\[500px\\] img",
|
||||
".w-[500px].h-[500px] img",
|
||||
".bg-floral-white img",
|
||||
"section img[alt]",
|
||||
];
|
||||
|
||||
for (const sel of imageCandidates) {
|
||||
const el = qsSafe(sel);
|
||||
if (el && el.src) {
|
||||
productImage = el.src;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!productImage) {
|
||||
const anyImg = qsSafe("img[alt]") || qsSafe("section img") || qsSafe("img");
|
||||
productImage = anyImg?.src || "";
|
||||
}
|
||||
|
||||
return {
|
||||
id: parseInt(productId),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue