khy_admin/admin-dashboard/scripts/main.js

1561 lines
51 KiB
JavaScript

// Global script initialization test
console.log("=== MAIN.JS LOADED ===");
console.log("Current pathname:", window.location.pathname);
console.log(
"Is comparison page:",
window.location.pathname.includes("product-comparison.html")
);
// Helper function to fix image paths for admin dashboard preview
function fixImagePath(imagePath) {
if (!imagePath) return imagePath;
// If the path starts with "assets/", prepend "../" for admin dashboard preview
if (imagePath.startsWith("assets/")) {
return "../" + imagePath;
}
return imagePath;
}
// Update year in footer and handle smooth scrolling
function initSite() {
// Update footer year
const footer = document.querySelector("footer p");
if (footer) {
const currentYear = new Date().getFullYear();
footer.innerHTML = footer.innerHTML.replace("2024", currentYear);
}
// Smooth scrolling for navigation links
const navLinks = document.querySelectorAll('.nav-link[href^="#"]');
navLinks.forEach((link) => {
link.addEventListener("click", function (e) {
e.preventDefault();
const targetId = this.getAttribute("href").substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
const headerHeight = 112;
const targetPosition = targetElement.offsetTop - headerHeight;
window.scrollTo({ top: targetPosition, behavior: "smooth" });
}
});
});
// Handle cross-page navigation links (links that point to other pages with anchors)
const crossPageLinks = document.querySelectorAll('.nav-link[href*=".html#"]');
crossPageLinks.forEach((link) => {
link.addEventListener("click", function () {
// allow default navigation
});
});
// Remove any lingering .active classes and avoid adding new ones
const allNavLinks = document.querySelectorAll(".nav-link");
allNavLinks.forEach((a) => a.classList.remove("active"));
// Do not add page-specific active state anymore
// const currentPage = window.location.pathname.split("/").pop() || "index.html";
// const currentPageLink = document.querySelector(`.nav-link[href="${currentPage}"]`);
// if (currentPageLink) currentPageLink.classList.add("active");
// Disable scroll-based active highlighting
// (Keeping function for potential future use, but it does nothing now.)
function updateActiveLink() {
// no-op: active highlighting disabled globally
}
window.addEventListener("scroll", updateActiveLink);
updateActiveLink();
// Related products (dynamic)
(async function initRelated() {
const grid = document.getElementById("related-grid");
if (!grid) return;
// Don't run this function on product detail pages - let the product detail function handle it
const urlParams = new URLSearchParams(window.location.search);
const productId = urlParams.get("id");
if (productId) return;
try {
const res = await fetch("data/products.json", { cache: "no-store" });
const data = await res.json();
const products = Array.isArray(data.products) ? data.products : [];
// Determine current product's category from the title text (fallback seating)
const title = document.querySelector("h1");
const currentName = (title?.textContent || "").trim();
const current = products.find(
(p) => (p.name || "").trim() === currentName
);
const category = current?.category || "seating";
// Filter related: same category but not the current product
const related = products.filter(
(p) => p.category === category && p.name !== currentName
);
let page = 1;
const pageSize = 4;
function render() {
grid.innerHTML = "";
const start = 0;
const end = page * pageSize; // cumulative show-more
related.slice(start, end).forEach((p) => {
const card = document.createElement("article");
card.className = "rounded-lg overflow-hidden bg-white shadow-sm";
// Distinct image background for Asgaard sofa to match others
const imageBgClass =
(p.name || "").toLowerCase() === "asgaard sofa"
? "bg-linen"
: "bg-white";
const panelBgClass = "bg-light-bg";
card.innerHTML = `
<div class=\"h-72 ${imageBgClass} flex items-center justify-center\">
<img src=\"${fixImagePath(p.image)}\" alt=\"${
p.alt || p.name
}\" class=\"w-full h-full object-cover\" />
</div>
<div class=\"${panelBgClass} p-6\">
<h3 class=\"font-poppins font-semibold text-2xl text-[#3A3A3A] mb-0\">${
p.name
}</h3>
</div>`;
grid.appendChild(card);
});
// Toggle show-more visibility
const btn = document.getElementById("related-show-more");
if (btn) {
const hasMore = related.length > page * pageSize;
btn.style.display = hasMore ? "inline-flex" : "none";
// Ensure centered label
btn.classList.add("inline-flex", "items-center", "justify-center");
}
}
const btn = document.getElementById("related-show-more");
if (btn) {
btn.addEventListener("click", () => {
page += 1;
render();
});
}
render();
} catch (e) {
console.error("Failed to load related products:", e);
}
})();
// Footer newsletter subscribe validation and feedback (works on all pages)
const siteFooter = document.querySelector("footer");
if (siteFooter) {
const emailInputs = siteFooter.querySelectorAll('input[type="email"]');
emailInputs.forEach((emailInput) => {
const inputRow = emailInput.closest(".flex") || emailInput.parentElement;
let subscribeButton = inputRow ? inputRow.querySelector("button") : null;
if (!subscribeButton) {
subscribeButton = emailInput.parentElement?.querySelector("button");
}
if (!subscribeButton) return;
subscribeButton.type = "button";
let feedback = inputRow ? inputRow.nextElementSibling : null;
if (!(feedback instanceof HTMLElement) || !feedback.dataset.feedback) {
feedback = document.createElement("div");
feedback.dataset.feedback = "newsletter";
if (inputRow && inputRow.parentElement) {
inputRow.parentElement.insertBefore(feedback, inputRow.nextSibling);
}
}
feedback.className =
"hidden mt-3 rounded-lg px-4 py-3 font-playfair text-base";
function showMessage(text, type) {
feedback.textContent = text;
feedback.className =
"mt-3 rounded-lg px-4 py-3 font-playfair text-base";
if (type === "success") {
feedback.classList.add(
"bg-green-50",
"border",
"border-green-200",
"text-green-800"
);
} else {
feedback.classList.add(
"bg-red-50",
"border",
"border-red-200",
"text-red-800"
);
}
feedback.classList.remove("hidden");
setTimeout(() => feedback.classList.add("hidden"), 3000);
}
subscribeButton.addEventListener("click", (e) => {
e.preventDefault();
const value = (emailInput.value || "").trim();
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
emailInput.classList.remove("border-red-500");
if (!emailRegex.test(value)) {
emailInput.classList.add("border-red-500");
showMessage("Please enter a valid email address.", "error");
emailInput.focus();
return;
}
showMessage("Thank you for subscribing!", "success");
emailInput.value = "";
subscribeButton.disabled = true;
setTimeout(() => (subscribeButton.disabled = false), 1200);
});
});
}
}
// Image enlargement modal functionality (global)
function addImageEnlargementListeners() {
// Target both main product image AND gallery carousel images
const mainProductImage = document.querySelector(
".w-full.h-80.md\\:w-\\[500px\\].md\\:h-\\[500px\\] img[data-enlarge-src]"
);
const galleryImages = document.querySelectorAll(
"#product-gallery-images img[data-enlarge-src]"
);
const modal = document.getElementById("image-modal");
const modalImage = document.getElementById("modal-image");
const modalCloseBtn = document.getElementById("modal-close-btn");
console.log("Adding image enlargement listeners...");
console.log("Found main product image:", !!mainProductImage);
console.log("Found gallery images:", galleryImages.length);
console.log("Modal elements:", {
modal: !!modal,
modalImage: !!modalImage,
modalCloseBtn: !!modalCloseBtn,
});
if (!modal || !modalImage || !modalCloseBtn) {
console.log("Modal elements not found, skipping image enlargement setup");
return;
}
// Add click listener to main product image
if (mainProductImage) {
console.log(
`Adding click listener to main product image:`,
mainProductImage.src
);
mainProductImage.removeEventListener("click", handleImageClick);
mainProductImage.addEventListener("click", handleImageClick);
} else {
console.log("Main product image not found");
}
// Add click listeners to gallery carousel images
galleryImages.forEach((img, index) => {
console.log(
`Adding click listener to gallery image ${index + 1}:`,
img.src
);
img.removeEventListener("click", handleImageClick);
img.addEventListener("click", handleImageClick);
});
function handleImageClick(e) {
console.log("Image clicked!", this.src);
const imageSrc = this.getAttribute("data-enlarge-src");
const imageAlt = this.getAttribute("alt");
console.log("Opening modal with image:", imageSrc);
modalImage.src = imageSrc;
modalImage.alt = imageAlt;
// Show modal with animation
modal.classList.remove("hidden");
document.body.style.overflow = "hidden"; // Prevent background scrolling
// Trigger animation after a brief delay
setTimeout(() => {
modalImage.classList.remove("scale-95");
modalImage.classList.add("scale-100");
}, 10);
}
// Close modal functionality
function closeModal() {
// Animate out
modalImage.classList.remove("scale-100");
modalImage.classList.add("scale-95");
// Hide modal after animation
setTimeout(() => {
modal.classList.add("hidden");
document.body.style.overflow = ""; // Restore scrolling
}, 300);
}
modalCloseBtn.addEventListener("click", closeModal);
// Close modal when clicking outside the image
modal.addEventListener("click", function (e) {
if (e.target === modal) {
closeModal();
}
});
// Close modal with Escape key
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && !modal.classList.contains("hidden")) {
closeModal();
}
});
}
// Thumbnail click functionality (global)
function addThumbnailClickListeners() {
const thumbnails = document.querySelectorAll("[data-thumbnail-src]");
const mainImageContainer = document.querySelector(
".w-full.h-80.md\\:w-\\[500px\\].md\\:h-\\[500px\\]"
);
console.log("Adding thumbnail click listeners...");
console.log("Found thumbnails:", thumbnails.length);
console.log("Main image container:", !!mainImageContainer);
if (!mainImageContainer) {
console.log("Main image container not found");
return;
}
thumbnails.forEach((thumbnail, index) => {
thumbnail.addEventListener("click", function () {
const imageSrc = this.getAttribute("data-thumbnail-src");
console.log(`Thumbnail ${index + 1} clicked, switching to:`, imageSrc);
// Update the main product image
const mainImg = mainImageContainer.querySelector("img");
if (mainImg) {
mainImg.src = imageSrc;
mainImg.setAttribute("data-enlarge-src", imageSrc);
console.log("Main image updated to:", imageSrc);
}
});
});
}
// Function to update product details (for preview updates)
function updateProductDetails(product) {
console.log("Updating product details with:", product);
// Update page title
document.title = `${product.name} - KHY`;
// Update the "Product Details" title with the actual product name
const productDetailsTitle = document.getElementById("product-details-title");
if (productDetailsTitle) {
productDetailsTitle.textContent = product.name;
}
// Update product title
const productTitle = document.getElementById("product-title");
if (productTitle) {
productTitle.textContent = product.name;
}
// Update product description
const productDescription = document.getElementById("product-description");
if (productDescription) {
productDescription.textContent = product.description;
}
// Update long description
const productDescriptionContent = document.getElementById(
"product-description-content"
);
if (productDescriptionContent && product.descriptionLong) {
if (Array.isArray(product.descriptionLong)) {
productDescriptionContent.innerHTML = product.descriptionLong
.map((para) => `<p>${para}</p>`)
.join("");
} else {
productDescriptionContent.innerHTML = `<p>${product.descriptionLong}</p>`;
}
}
// Update specifications
const specificationsContainer = document.getElementById(
"product-specifications"
);
if (specificationsContainer && product.additionalInformation) {
specificationsContainer.innerHTML = "";
Object.entries(product.additionalInformation).forEach(([key, value]) => {
if (value) {
const specItem = document.createElement("div");
specItem.className = "flex justify-between items-center py-1";
specItem.innerHTML = `
<span class="text-gray-600 font-medium">${key}:</span>
<span class="text-gray-800">${value}</span>
`;
specificationsContainer.appendChild(specItem);
}
});
}
// Update images
if (product.images && product.images.length > 0) {
// Update main image
const mainImg = document.getElementById("main-product-image");
if (mainImg) {
const imageSrc = fixImagePath(product.images[0]);
mainImg.src = imageSrc;
mainImg.setAttribute("data-enlarge-src", imageSrc);
}
// Update thumbnails
const thumbnailContainer = document.getElementById("thumbnail-container");
if (thumbnailContainer) {
thumbnailContainer.innerHTML = "";
product.images.forEach((img, index) => {
const thumbnail = document.createElement("img");
thumbnail.src = fixImagePath(img);
thumbnail.alt = `Product image ${index + 1}`;
thumbnail.className =
"thumbnail cursor-pointer transition-opacity duration-200 hover:opacity-70";
thumbnail.setAttribute("data-thumbnail-src", fixImagePath(img));
thumbnailContainer.appendChild(thumbnail);
});
}
}
console.log("Product details updated successfully");
}
// Make the function globally available
window.updateProductDetails = updateProductDetails;
// Product detail page functionality
async function initProductDetail() {
console.log("Product detail script running...");
console.log("Current URL:", window.location.href);
// Check if we're on the product detail page
const productTitle = document.querySelector("h1");
if (!productTitle) {
console.log("No h1 found, not on product detail page");
return;
}
console.log("Found h1 element:", productTitle);
// Get product ID from URL
const urlParams = new URLSearchParams(window.location.search);
const productId = parseInt(urlParams.get("id"));
console.log("Product ID from URL:", productId);
if (!productId) {
console.log("No product ID found in URL");
return;
}
try {
// Load product data
const response = await fetch("data/products.json");
const data = await response.json();
const product = data.products.find((p) => p.id === productId);
if (!product) {
console.error("Product not found:", productId);
return;
}
console.log("Loading product:", product);
// Update page title
document.title = `${product.name} - KHY`;
// Update the "Product Details" title with the actual product name
const productDetailsTitle = document.getElementById(
"product-details-title"
);
if (productDetailsTitle) {
productDetailsTitle.textContent = product.name;
}
// Update product title (the main product title, not the breadcrumb)
const productTitle = document.getElementById("product-title");
console.log("Product title element:", productTitle);
if (productTitle) {
productTitle.textContent = product.name;
console.log("Updated product title to:", product.name);
}
// Update product description
const productDescription = document.getElementById("product-description");
console.log("Product description element:", productDescription);
if (productDescription) {
productDescription.textContent = product.description;
console.log("Updated product description to:", product.description);
}
// Update main product image
const mainImageContainer = document.querySelector(
".w-full.h-80.md\\:w-\\[500px\\].md\\:h-\\[500px\\]"
);
console.log("Main image container:", mainImageContainer);
if (mainImageContainer) {
mainImageContainer.innerHTML = `
<img
src="${fixImagePath(product.image)}"
alt="${product.alt || product.name}"
class="w-full h-full object-cover cursor-pointer hover:opacity-90 transition-opacity"
data-enlarge-src="${fixImagePath(product.image)}"
/>
`;
console.log("Updated main image to:", product.image);
// Add image enlargement functionality to the main product image
setTimeout(() => {
addImageEnlargementListeners();
}, 100);
}
// Update thumbnail images
const thumbnailContainer = document.querySelector(
".flex.flex-row.md\\:flex-col.gap-3.md\\:gap-4"
);
console.log("Thumbnail container:", thumbnailContainer);
if (thumbnailContainer && product.images) {
thumbnailContainer.innerHTML = product.images
.slice(0, 4)
.map(
(img, index) => `
<div class="w-32 h-32 bg-floral-white rounded-lg overflow-hidden cursor-pointer hover:opacity-80 transition-opacity" data-thumbnail-src="${fixImagePath(
img
)}">
<img
src="${fixImagePath(img)}"
alt="${product.name} ${index + 1}"
class="w-full h-full object-cover"
/>
</div>
`
)
.join("");
console.log("Updated thumbnails with", product.images.length, "images");
// Add click event listeners to thumbnails
addThumbnailClickListeners();
}
// Update product specifications
const specificationsContainer = document.getElementById(
"product-specifications"
);
console.log("Specifications container:", specificationsContainer);
if (specificationsContainer && product.additionalInformation) {
const specifications = [];
// Add key specifications from additionalInformation
if (product.additionalInformation.Material) {
specifications.push({
label: "Material",
value: product.additionalInformation.Material,
});
}
if (product.additionalInformation.Design) {
specifications.push({
label: "Design",
value: product.additionalInformation.Design,
});
}
if (product.additionalInformation["Finish Options"]) {
specifications.push({
label: "Finish Options",
value: product.additionalInformation["Finish Options"],
});
}
if (product.additionalInformation.Headrest) {
specifications.push({
label: "Headrest",
value: product.additionalInformation.Headrest,
});
}
if (product.additionalInformation["Use Cases"]) {
specifications.push({
label: "Use Cases",
value: product.additionalInformation["Use Cases"],
});
}
if (product.additionalInformation.Ergonomics) {
specifications.push({
label: "Ergonomics",
value: product.additionalInformation.Ergonomics,
});
}
if (product.additionalInformation.Maintenance) {
specifications.push({
label: "Maintenance",
value: product.additionalInformation.Maintenance,
});
}
if (product.additionalInformation.Durability) {
specifications.push({
label: "Durability",
value: product.additionalInformation.Durability,
});
}
if (product.additionalInformation.Warranty) {
specifications.push({
label: "Warranty",
value: product.additionalInformation.Warranty,
});
}
// Render specifications
specificationsContainer.innerHTML = specifications
.map(
(spec) => `
<div class="flex justify-between items-start py-1 border-b border-gray-100 last:border-b-0">
<span class="font-playfair font-normal text-xs text-quick-silver flex-shrink-0 mr-4">
${spec.label}:
</span>
<span class="font-playfair font-normal text-xs text-black text-right">
${spec.value}
</span>
</div>
`
)
.join("");
console.log(
"Updated specifications with",
specifications.length,
"items"
);
}
// Update product metadata - find by text content
const allSpans = document.querySelectorAll("span");
// Find and update Model No.
const modelNoLabel = Array.from(allSpans).find(
(span) => span.textContent === "Model No."
);
if (modelNoLabel && product.modelNo) {
const modelNoValue =
modelNoLabel.parentElement.querySelector("span:last-child");
if (modelNoValue) {
modelNoValue.textContent = product.modelNo;
}
}
// Find and update Category
const categoryLabel = Array.from(allSpans).find(
(span) => span.textContent === "Category"
);
if (categoryLabel && product.category) {
const categoryValue =
categoryLabel.parentElement.querySelector("span:last-child");
if (categoryValue) {
categoryValue.textContent =
product.category.charAt(0).toUpperCase() + product.category.slice(1);
}
}
// Find and update Dimensions
const dimensionsLabel = Array.from(allSpans).find(
(span) => span.textContent === "Dimension"
);
console.log("Dimensions label found:", dimensionsLabel);
console.log("Product dimensions:", product.dimensions);
if (dimensionsLabel && product.dimensions) {
const dimensionsValue =
dimensionsLabel.parentElement.querySelector("span:last-child");
console.log("Dimensions value element:", dimensionsValue);
if (dimensionsValue) {
dimensionsValue.textContent = product.dimensions;
console.log("Updated dimensions to:", product.dimensions);
}
}
// Update description content
const descriptionContainer = document.getElementById(
"product-description-content"
);
console.log("Description content container:", descriptionContainer);
if (descriptionContainer && product.descriptionLong) {
descriptionContainer.innerHTML = product.descriptionLong
.map(
(paragraph) => `
<p class="font-playfair text-base leading-6 text-[#333333] text-justify">
${paragraph}
</p>
`
)
.join("");
console.log(
"Updated description content with",
product.descriptionLong.length,
"paragraphs"
);
}
// Update gallery images with carousel
const galleryContainer = document.getElementById("product-gallery-images");
const galleryBackBtn = document.getElementById("gallery-back-btn");
const galleryNextBtn = document.getElementById("gallery-next-btn");
console.log("Gallery container:", galleryContainer);
console.log("Product galleryPairs:", product.galleryPairs);
if (galleryContainer && product.galleryPairs) {
// galleryPairs is now a simple array of image paths
const allGalleryImages = product.galleryPairs;
console.log("All gallery images:", allGalleryImages);
// Store gallery images for carousel
window.currentGalleryImages = allGalleryImages;
window.currentGalleryIndex = 0;
console.log("About to call renderGalleryCarousel...");
// Render initial gallery view
renderGalleryCarousel();
// Show navigation arrows for looped carousel (always show if more than 2 images)
if (allGalleryImages.length > 2) {
galleryBackBtn.style.display = "block";
galleryNextBtn.style.display = "block";
} else {
galleryBackBtn.style.display = "none";
galleryNextBtn.style.display = "none";
}
console.log(
"Gallery carousel:",
allGalleryImages.length,
"gallery images total (sliding)"
);
}
function renderGalleryCarousel() {
console.log("renderGalleryCarousel called");
console.log("window.currentGalleryImages:", window.currentGalleryImages);
console.log("galleryContainer:", galleryContainer);
if (!window.currentGalleryImages || !galleryContainer) {
console.log(
"Early return: missing currentGalleryImages or galleryContainer"
);
return;
}
console.log(
"Rendering gallery carousel with",
window.currentGalleryImages.length,
"images"
);
// Handle single image vs multiple images
if (window.currentGalleryImages.length === 1) {
// Single image - show only one image, hide arrows
const image1 = window.currentGalleryImages[0];
console.log("Rendering single image:", image1);
galleryContainer.innerHTML = `
<div class="rounded-[10px] bg-floral-white p-6 transition-all duration-1500 ease-out cursor-pointer hover:opacity-90" id="gallery-image-1">
<img
src="${image1}"
alt="${product.name} gallery"
class="w-full h-80 object-contain mx-auto"
data-enlarge-src="${image1}"
/>
</div>
`;
// Hide arrows for single image
galleryBackBtn.style.display = "none";
galleryNextBtn.style.display = "none";
} else {
// Multiple images - show 2 images with carousel
const image1 = window.currentGalleryImages[window.currentGalleryIndex];
const image2Index =
(window.currentGalleryIndex + 1) % window.currentGalleryImages.length;
const image2 = window.currentGalleryImages[image2Index];
console.log("Rendering multiple images:", image1, image2);
galleryContainer.innerHTML = `
<div class="rounded-[10px] bg-floral-white p-6 transition-all duration-1500 ease-out cursor-pointer hover:opacity-90" id="gallery-image-1">
<img
src="${image1}"
alt="${product.name} gallery"
class="w-full h-80 object-contain mx-auto"
data-enlarge-src="${image1}"
/>
</div>
<div class="rounded-[10px] bg-floral-white p-6 transition-all duration-1500 ease-out cursor-pointer hover:opacity-90" id="gallery-image-2">
<img
src="${image2}"
alt="${product.name} gallery"
class="w-full h-80 object-contain mx-auto"
data-enlarge-src="${image2}"
/>
</div>
`;
// Show arrows for multiple images
galleryBackBtn.style.display = "block";
galleryBackBtn.style.opacity = "1";
galleryBackBtn.style.pointerEvents = "auto";
galleryNextBtn.style.display = "block";
galleryNextBtn.style.opacity = "1";
galleryNextBtn.style.pointerEvents = "auto";
}
// Add click event listeners to gallery images for enlargement
console.log("About to call addImageEnlargementListeners for gallery...");
addImageEnlargementListeners();
}
// Add click handlers for looped gallery carousel navigation
if (galleryBackBtn) {
galleryBackBtn.addEventListener("click", function () {
// Left arrow moves forward: if at last position, go to 0
window.currentGalleryIndex =
(window.currentGalleryIndex + 1) % window.currentGalleryImages.length;
renderGalleryCarousel();
});
}
if (galleryNextBtn) {
galleryNextBtn.addEventListener("click", function () {
// Right arrow moves backward: if at 0, go to last position
window.currentGalleryIndex =
window.currentGalleryIndex === 0
? window.currentGalleryImages.length - 1
: window.currentGalleryIndex - 1;
renderGalleryCarousel();
});
}
// Update related products section
const relatedGrid = document.getElementById("related-grid");
if (relatedGrid && product.category) {
console.log("Current product category:", product.category);
console.log(
"All products:",
data.products.map((p) => ({
id: p.id,
name: p.name,
category: p.category,
}))
);
// Filter related products by category (excluding current product)
const allRelatedProducts = data.products.filter(
(p) => p.category === product.category && p.id !== product.id
);
console.log("All related products found:", allRelatedProducts);
let currentPage = 1;
const pageSize = 4;
function renderRelatedProducts() {
const start = 0;
const end = currentPage * pageSize;
const productsToShow = allRelatedProducts.slice(start, end);
relatedGrid.innerHTML = productsToShow
.map(
(p) => `
<a href="../product-detail.html?id=${p.id}" class="block">
<div class="rounded-lg overflow-hidden bg-white shadow-sm hover:shadow-lg transition-shadow">
<div class="h-72 ${
p.name.toLowerCase().includes("asgaard")
? "bg-linen"
: "bg-white"
} flex items-center justify-center">
<img src="${fixImagePath(p.image)}" alt="${
p.alt || p.name
}" class="w-full h-full object-cover" />
</div>
<div class="bg-light-bg p-6">
<h3 class="font-poppins font-semibold text-2xl text-[#3A3A3A] mb-0">${
p.name
}</h3>
</div>
</div>
</a>
`
)
.join("");
// Handle "Show More" button visibility
const showMoreBtn = document.getElementById("related-show-more");
if (showMoreBtn) {
const hasMore = allRelatedProducts.length > end;
showMoreBtn.style.display = hasMore ? "inline-flex" : "none";
showMoreBtn.classList.add(
"inline-flex",
"items-center",
"justify-center"
);
}
}
// Add event listener for "Show More" button
const showMoreBtn = document.getElementById("related-show-more");
if (showMoreBtn) {
showMoreBtn.addEventListener("click", () => {
currentPage += 1;
renderRelatedProducts();
});
}
// Initial render
renderRelatedProducts();
}
} catch (error) {
console.error("Error loading product data:", error);
}
}
// Product Comparison Page Functionality
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");
const product2Id = urlParams.get("product2");
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) => {
console.log("Fetch response status:", response.status);
return response.json();
})
.then((data) => {
console.log("Products data loaded:", data);
console.log("Total products:", data.products.length);
// Find products by ID
const product1 = data.products.find((p) => p.id == product1Id);
const product2 = data.products.find((p) => p.id == product2Id);
console.log("Found products:", { product1, product2 });
// 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);
}
// Populate dropdown
populateProductDropdown(data.products);
// Update View More link with current comparison state
updateViewMoreLink(product1Id, product2Id);
})
.catch((error) => {
console.error("Error loading products:", error);
});
}
function updateProductCard(slotNumber, product) {
console.log(`=== UPDATING PRODUCT CARD ${slotNumber} ===`);
console.log("Product data:", product);
const cardContainer = document.querySelector(`.product-card-${slotNumber}`);
console.log("Card container found:", cardContainer);
if (cardContainer) {
const imageContainer = cardContainer.querySelector("div");
const title = cardContainer.querySelector("p");
console.log("Image container found:", imageContainer);
console.log("Title element found:", title);
if (imageContainer) {
console.log("Replacing image container with:", product.image);
// Replace the placeholder div with an image
imageContainer.innerHTML = `<img src="${fixImagePath(
product.image
)}" alt="${product.name}" class="w-full h-full object-cover rounded-lg">`;
}
if (title) {
console.log("Updating title to:", product.name);
title.textContent = product.name;
}
} else {
console.log(`Product card container .product-card-${slotNumber} not found`);
}
}
function updateComparisonTable(product, slotNumber) {
console.log(`=== UPDATING COMPARISON TABLE FOR SLOT ${slotNumber} ===`);
console.log("Product:", product);
// Update only sections present in the HTML
const sections = ["general", "warranty"];
sections.forEach((section) => {
console.log(`Updating ${section} section...`);
updateTableSection(section, product, slotNumber);
});
}
function updateTableSection(sectionName, product, slotNumber) {
console.log(
`=== UPDATING TABLE SECTION: ${sectionName} (SLOT ${slotNumber}) ===`
);
const sectionData = getProductSectionData(product, sectionName);
// Find the section header
const section = document.querySelector(
`.comparison-table .${sectionName}-section`
);
if (!section) {
console.log(`Section ${sectionName}-section not found`);
return;
}
// Find the table that comes after this section header
const sectionTable = section.nextElementSibling;
if (!sectionTable) {
console.log(`Table after ${sectionName}-section not found`);
return;
}
// Find all flex rows and filter to only those with data columns
const allRows = sectionTable.querySelectorAll(".flex.items-center");
const rows = Array.from(allRows).filter((row) =>
row.querySelector(".column-1")
);
console.log(
`Found ${rows.length} data rows in ${sectionName} section (out of ${allRows.length} total rows)`
);
if (rows.length > 0 && sectionData) {
console.log("Updating rows with data:", sectionData);
// Update each row with the corresponding data
rows.forEach((row, index) => {
if (index < sectionData.length) {
const column = row.querySelector(`.column-${slotNumber}`);
if (column) {
console.log(
`Updating row ${index + 1} with data: ${sectionData[index]}`
);
console.log(`Row element:`, row);
console.log(`Column element:`, column);
console.log(`Column text before update: "${column.textContent}"`);
column.textContent = sectionData[index];
console.log(`Column text after update: "${column.textContent}"`);
} else {
console.log(`Column ${slotNumber} not found in row ${index + 1}`);
}
}
});
console.log("Table section updated successfully.");
} else {
console.log("No rows found or section data is empty, skipping update.");
console.log("Rows found:", rows.length);
console.log("Section data:", sectionData);
}
}
function getProductSectionData(product, sectionName) {
console.log(`=== GETTING PRODUCT SECTION DATA: ${sectionName} ===`);
console.log("Product:", product);
let sectionData;
switch (sectionName) {
case "general":
sectionData = [
product.additionalInformation?.Material || "N/A", // Materials
product.additionalInformation?.Design || "N/A", // Design
product.additionalInformation?.["Use Cases"] || "N/A", // Use Cases
];
break;
case "warranty":
sectionData = [
product.additionalInformation?.Warranty || "N/A", // Warranty Summary only
];
break;
default:
sectionData = [];
}
console.log(`Section data for ${sectionName}:`, sectionData);
console.log(`Detailed breakdown for ${sectionName}:`);
sectionData.forEach((item, index) => {
console.log(` Item ${index + 1}: "${item}"`);
});
return sectionData;
}
function populateProductDropdown(products) {
const dropdown = document.getElementById("product-dropdown");
if (dropdown) {
// Clear existing options except the first one
while (dropdown.children.length > 1) {
dropdown.removeChild(dropdown.lastChild);
}
// Add all products
products.forEach((product) => {
const option = document.createElement("option");
option.value = product.id;
option.textContent = product.name;
dropdown.appendChild(option);
});
// Add event listener for product selection
dropdown.addEventListener("change", function () {
const selectedProductId = this.value;
console.log("Product selected from dropdown:", selectedProductId);
if (selectedProductId && selectedProductId !== "Choose a Product") {
// Find the selected product
const selectedProduct = products.find((p) => p.id == selectedProductId);
if (selectedProduct) {
console.log("Selected product found:", selectedProduct);
// Update the second product slot
updateProductCard(2, selectedProduct);
updateComparisonTable(selectedProduct, 2);
// Update URL to include the second product
updateURLParameter("product2", selectedProductId);
// Reset dropdown to default option
this.value = "Choose a Product";
}
}
});
}
}
function updateURLParameter(param, value) {
const url = new URL(window.location);
url.searchParams.set(param, value);
window.history.replaceState({}, "", url);
}
function updateViewMoreLink(product1Id, product2Id) {
const viewMoreLink = document.querySelector(
'a[href*="product-catalog.html"]'
);
if (viewMoreLink) {
// Determine which slot is available (1 or 2)
let availableSlot = 1;
if (!product1Id) {
availableSlot = 1;
} else if (!product2Id) {
availableSlot = 2;
} else {
// Both slots are filled, default to slot 2 for replacement
availableSlot = 2;
}
let newHref = `product-catalog.html?returnTo=comparison&slot=${availableSlot}`;
if (product1Id) newHref += `&product1=${product1Id}`;
if (product2Id) newHref += `&product2=${product2Id}`;
viewMoreLink.href = newHref;
console.log("Updated View More link:", newHref);
}
}
// Initialize product comparison if on comparison page
console.log("=== CHECKING IF COMPARISON PAGE INITIALIZATION SHOULD RUN ===");
console.log(
"Pathname includes product-comparison.html:",
window.location.pathname.includes("product-comparison.html")
);
if (window.location.pathname.includes("product-comparison.html")) {
console.log("Product comparison page detected, initializing immediately");
initProductComparison();
// Also try on DOMContentLoaded as backup
document.addEventListener("DOMContentLoaded", function () {
console.log("Product comparison page DOMContentLoaded backup");
initProductComparison();
});
}
// Product Detail Page - Compare Products functionality
function initProductDetailCompare() {
console.log("=== INITIALIZING PRODUCT DETAIL COMPARE ===");
console.log("Current URL:", window.location.href);
console.log("Pathname:", window.location.pathname);
// Try to find the button immediately
let compareButton = document.getElementById("compare-products-btn");
console.log("Button found by ID:", compareButton);
if (!compareButton) {
console.log("Button not found by ID, trying text search...");
const buttons = document.querySelectorAll("button");
console.log("Total buttons found:", buttons.length);
buttons.forEach((button, index) => {
console.log(`Button ${index}: "${button.textContent.trim()}"`);
});
compareButton = Array.from(buttons).find(
(button) => button.textContent.trim() === "Compare Products"
);
console.log("Button found by text search:", compareButton);
}
if (compareButton) {
console.log("=== ADDING CLICK LISTENER ===");
// Remove any existing listeners first
compareButton.removeEventListener("click", handleCompareClick);
compareButton.addEventListener("click", handleCompareClick);
// Also add a direct onclick handler as backup
compareButton.onclick = handleCompareClick;
console.log("Click listener added successfully");
console.log("Button element:", compareButton);
console.log("Button text content:", compareButton.textContent);
} else {
console.log("=== BUTTON NOT FOUND ===");
console.log("Compare Products button not found");
}
}
// Separate function for the click handler
function handleCompareClick(event) {
console.log("Compare Products button clicked");
event.preventDefault();
event.stopPropagation();
// Get current product ID from URL
const urlParams = new URLSearchParams(window.location.search);
const productId = urlParams.get("id");
console.log("Product ID from URL:", productId);
if (productId) {
// Navigate to comparison page with current product as product1
const comparisonUrl = `product-comparison.html?product1=${productId}`;
console.log("Navigating to:", comparisonUrl);
window.location.href = comparisonUrl;
} else {
// If no product ID, just go to comparison page
console.log("No product ID found, navigating to comparison page");
window.location.href = "product-comparison.html";
}
}
// Initialize immediately if we're on the product detail page
if (window.location.pathname.includes("product-detail.html")) {
console.log(
"Product detail page detected, initializing compare functionality immediately"
);
initProductDetailCompare();
// Also initialize product detail loading
initProductDetail();
}
// Also try to initialize on DOMContentLoaded
document.addEventListener("DOMContentLoaded", function () {
console.log("DOMContentLoaded event fired");
if (window.location.pathname.includes("product-detail.html")) {
console.log("Product detail page detected in DOMContentLoaded");
initProductDetailCompare();
// Also initialize product detail loading
initProductDetail();
}
});
// Initialize product comparison if on comparison page
if (window.location.pathname.includes("product-comparison.html")) {
document.addEventListener("DOMContentLoaded", function () {
initProductComparison();
});
}
// Initialize comparison functionality if on product catalog page
if (window.location.pathname.includes("product-catalog.html")) {
console.log("=== PRODUCT CATALOG PAGE DETECTED ===");
document.addEventListener("DOMContentLoaded", function () {
console.log(
"=== DOM CONTENT LOADED - INITIALIZING PRODUCT CATALOG COMPARISON ==="
);
initProductCatalogComparison();
});
}
// Product Catalog - Handle comparison page returns
function initProductCatalogComparison() {
const urlParams = new URLSearchParams(window.location.search);
const returnTo = urlParams.get("returnTo");
const slot = urlParams.get("slot");
const product1Id = urlParams.get("product1");
const product2Id = urlParams.get("product2");
console.log("Product catalog comparison params:", {
returnTo,
slot,
product1Id,
product2Id,
});
if (returnTo === "comparison" && slot) {
console.log("Setting up comparison return functionality for slot:", slot);
// Note: Product card click handling is now done in products.js viewProduct method
console.log(
"Comparison mode activated - View buttons will navigate to comparison page"
);
}
}
// Replace Poppins with Playfair in all font references
function updateFontClasses() {
// Find all elements with font-poppins class and replace with font-playfair
const poppinsElements = document.querySelectorAll(".font-poppins");
poppinsElements.forEach((element) => {
element.classList.remove("font-poppins");
element.classList.add("font-playfair");
});
}
// Run font update on page load
document.addEventListener("DOMContentLoaded", function () {
updateFontClasses();
});
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initSite);
} else {
initSite();
}
// Initialize page functionality
document.addEventListener("DOMContentLoaded", function () {
initHeroCarousel();
initMobileMenu();
initCuratedCardsTap();
});
// Hero Carousel Functionality
function initHeroCarousel() {
const arrowButton = document.getElementById("story-arrow-button");
const heroImage = document.querySelector("#hero-image img");
if (!arrowButton || !heroImage) return;
// Carousel images array
const carouselImages = [
"../assets/images/our_story/chair.jpg",
"../assets/images/our_story/booth.png",
"../assets/images/our_story/screen.jpg",
"../assets/images/our_story/table.jpg",
"../assets/images/our_story/chair2.jpg",
"../assets/images/our_story/storage.jpg",
];
let currentImageIndex = 0;
// Function to update image with fade transition
function updateImage(newIndex) {
const newImage = new Image();
newImage.onload = function () {
// Fade out current image
heroImage.style.opacity = "0";
setTimeout(() => {
// Change image source
heroImage.src = carouselImages[newIndex];
heroImage.alt = `Carousel image ${newIndex + 1}`;
// Ensure image always fits its container uniformly
heroImage.style.height = "100%";
heroImage.style.objectFit = "cover";
// Fade in new image
heroImage.style.opacity = "1";
// Update indicators
updateIndicators(newIndex);
}, 300);
};
newImage.src = carouselImages[newIndex];
}
// Function to update carousel indicators
function updateIndicators(activeIndex) {
for (let i = 0; i < 6; i++) {
const indicator = document.getElementById(`carousel-indicator-${i}`);
if (indicator) {
indicator.style.opacity = i === activeIndex ? "1" : "0.5";
}
}
}
// Arrow button click handler
arrowButton.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
currentImageIndex = (currentImageIndex + 1) % carouselImages.length;
updateImage(currentImageIndex);
});
// Indicator click handlers
for (let i = 0; i < 6; i++) {
const indicator = document.getElementById(`carousel-indicator-${i}`);
if (indicator) {
indicator.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
currentImageIndex = i;
updateImage(currentImageIndex);
});
}
}
// No dynamic height capture needed; CSS handles sizing
// Auto-advance carousel every 5 seconds
setInterval(() => {
currentImageIndex = (currentImageIndex + 1) % carouselImages.length;
updateImage(currentImageIndex);
}, 5000);
}
// Tap-to-toggle for curated cards on touch devices
function initCuratedCardsTap() {
try {
const cards = document.querySelectorAll(".curated-card");
if (!cards || cards.length === 0) return;
// Only enable on coarse pointers (touch)
const isTouchLike = window.matchMedia(
"(hover: none), (pointer: coarse)"
).matches;
if (!isTouchLike) return;
cards.forEach((card) => {
card.addEventListener("click", (e) => {
// Toggle active state; second tap removes it
card.classList.toggle("is-active");
});
// Optional: remove active when tapping outside the card
document.addEventListener("click", (evt) => {
if (!card.contains(evt.target)) {
card.classList.remove("is-active");
}
});
});
} catch (err) {
console.warn("Failed to init curated card tap behavior:", err);
}
}
// Mobile Menu Functionality
function initMobileMenu() {
const mobileMenuButton = document.getElementById("mobile-menu-button");
const mobileMenuClose = document.getElementById("mobile-menu-close");
const mobileMenu = document.getElementById("mobile-menu");
const mobileMenuOverlay = document.getElementById("mobile-menu-overlay");
if (
!mobileMenuButton ||
!mobileMenuClose ||
!mobileMenu ||
!mobileMenuOverlay
) {
console.log("Mobile menu elements not found");
return;
}
// Function to open mobile menu
function openMobileMenu() {
mobileMenu.classList.remove("translate-x-full");
mobileMenuOverlay.classList.remove("hidden");
document.body.style.overflow = "hidden"; // Prevent background scrolling
}
// Function to close mobile menu
function closeMobileMenu() {
mobileMenu.classList.add("translate-x-full");
mobileMenuOverlay.classList.add("hidden");
document.body.style.overflow = ""; // Restore scrolling
}
// Event listeners
mobileMenuButton.addEventListener("click", openMobileMenu);
mobileMenuClose.addEventListener("click", closeMobileMenu);
mobileMenuOverlay.addEventListener("click", closeMobileMenu);
// Close menu when clicking on navigation links
const mobileNavLinks = mobileMenu.querySelectorAll("a");
mobileNavLinks.forEach((link) => {
link.addEventListener("click", closeMobileMenu);
});
// Close menu on escape key
document.addEventListener("keydown", (e) => {
if (
e.key === "Escape" &&
!mobileMenu.classList.contains("translate-x-full")
) {
closeMobileMenu();
}
});
// Handle window resize - close menu if screen becomes large
window.addEventListener("resize", () => {
if (window.innerWidth >= 640) {
// sm breakpoint
closeMobileMenu();
}
});
}
// Version: 4.8 - Added mobile hamburger menu functionality