mirror of
https://git.kh3group.com/georgebiri/khy_website.git
synced 2026-10-16 21:41:47 +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
201
scripts/main.js
201
scripts/main.js
|
|
@ -1054,6 +1054,13 @@ function initSite() {
|
||||||
function initProductComparison() {
|
function initProductComparison() {
|
||||||
console.log("=== INITIALIZING PRODUCT COMPARISON ===");
|
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
|
// Get product IDs from URL parameters
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const product1Id = urlParams.get("product1");
|
const product1Id = urlParams.get("product1");
|
||||||
|
|
@ -1061,6 +1068,10 @@ function initProductComparison() {
|
||||||
|
|
||||||
console.log("URL Parameters:", { product1Id, product2Id });
|
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 product data
|
||||||
fetch("data/products.json")
|
fetch("data/products.json")
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
|
@ -1080,12 +1091,14 @@ function initProductComparison() {
|
||||||
// Update product cards
|
// Update product cards
|
||||||
if (product1) {
|
if (product1) {
|
||||||
console.log("Updating product card 1 with:", product1.name);
|
console.log("Updating product card 1 with:", product1.name);
|
||||||
|
cmpProduct1 = product1;
|
||||||
updateProductCard(1, product1);
|
updateProductCard(1, product1);
|
||||||
updateComparisonTable(product1, 1);
|
updateComparisonTable(product1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (product2) {
|
if (product2) {
|
||||||
console.log("Updating product card 2 with:", product2.name);
|
console.log("Updating product card 2 with:", product2.name);
|
||||||
|
cmpProduct2 = product2;
|
||||||
updateProductCard(2, product2);
|
updateProductCard(2, product2);
|
||||||
updateComparisonTable(product2, 2);
|
updateComparisonTable(product2, 2);
|
||||||
}
|
}
|
||||||
|
|
@ -1095,12 +1108,113 @@ function initProductComparison() {
|
||||||
|
|
||||||
// Update View More link with current comparison state
|
// Update View More link with current comparison state
|
||||||
updateViewMoreLink(product1Id, product2Id);
|
updateViewMoreLink(product1Id, product2Id);
|
||||||
|
|
||||||
|
// Wire Add To Quote buttons (first -> product1, second -> product2)
|
||||||
|
wireComparisonAddToQuote(cmpProduct1, cmpProduct2);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Error loading products:", 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) {
|
function updateProductCard(slotNumber, product) {
|
||||||
console.log(`=== UPDATING PRODUCT CARD ${slotNumber} ===`);
|
console.log(`=== UPDATING PRODUCT CARD ${slotNumber} ===`);
|
||||||
console.log("Product data:", product);
|
console.log("Product data:", product);
|
||||||
|
|
@ -1537,20 +1651,59 @@ function initQuoteBadge() {
|
||||||
function initAddToQuote() {
|
function initAddToQuote() {
|
||||||
const addToQuoteBtn = document.getElementById("add-to-quote-btn");
|
const addToQuoteBtn = document.getElementById("add-to-quote-btn");
|
||||||
if (addToQuoteBtn) {
|
if (addToQuoteBtn) {
|
||||||
addToQuoteBtn.addEventListener("click", function () {
|
try {
|
||||||
// Get product data from the page
|
// 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();
|
const productData = getProductDataFromPage();
|
||||||
|
console.log("[AddToQuote] productData:", productData);
|
||||||
if (productData) {
|
if (productData) {
|
||||||
// Add to quote using the global function
|
|
||||||
if (typeof addToQuote === "function") {
|
if (typeof addToQuote === "function") {
|
||||||
addToQuote(productData);
|
addToQuote(productData);
|
||||||
} else {
|
} else {
|
||||||
// Fallback: directly use localStorage
|
|
||||||
addToQuoteFallback(productData);
|
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) {
|
||||||
|
if (typeof addToQuote === "function") {
|
||||||
|
addToQuote(productData);
|
||||||
|
} else {
|
||||||
|
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
|
// Get product data from the current page
|
||||||
|
|
@ -1569,12 +1722,40 @@ function getProductDataFromPage() {
|
||||||
const selectedSize = getSelectedSize();
|
const selectedSize = getSelectedSize();
|
||||||
const selectedQuantity = getSelectedQuantity();
|
const selectedQuantity = getSelectedQuantity();
|
||||||
|
|
||||||
// Get product name and image (you might need to adjust these selectors)
|
// Get product name and a best-effort product image
|
||||||
const productName = document.querySelector("h1")?.textContent || "Product";
|
const productName =
|
||||||
const productImage =
|
document.querySelector("h1")?.textContent?.trim() || "Product";
|
||||||
document.querySelector(".w-\\[500px\\].h-\\[500px\\] img")?.src ||
|
let productImage = "";
|
||||||
document.querySelector(".w-[500px].h-[500px] img")?.src ||
|
|
||||||
"";
|
// 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 {
|
return {
|
||||||
id: parseInt(productId),
|
id: parseInt(productId),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue