// Quote Management System class QuoteManager { constructor() { this.storageKey = "khy_quote_items"; this.quoteItems = this.loadQuoteItems(); this.init(); } // Load quote items from localStorage loadQuoteItems() { try { const stored = localStorage.getItem(this.storageKey); return stored ? JSON.parse(stored) : []; } catch (error) { console.error("Error loading quote items:", error); return []; } } // Save quote items to localStorage saveQuoteItems() { try { localStorage.setItem(this.storageKey, JSON.stringify(this.quoteItems)); this.updateQuoteBadge(); } catch (error) { console.error("Error saving quote items:", error); } } // Add item to quote addToQuote(productData) { const { id, name, image, color = "Default", size = "Standard", quantity = 1, } = productData; // Check if item already exists with same specifications const existingItemIndex = this.quoteItems.findIndex( (item) => item.id === id && item.color === color && item.size === size ); if (existingItemIndex !== -1) { // Update quantity of existing item this.quoteItems[existingItemIndex].quantity += quantity; } else { // Add new item const newItem = { id, name, image, color, size, quantity, timestamp: new Date().toISOString(), }; this.quoteItems.push(newItem); } this.saveQuoteItems(); this.renderQuoteItems(); this.showAddToQuoteSuccess(); } // Remove item from quote removeFromQuote(itemIndex) { this.quoteItems.splice(itemIndex, 1); this.saveQuoteItems(); this.renderQuoteItems(); } // Update item quantity updateQuantity(itemIndex, newQuantity) { if (newQuantity > 0) { this.quoteItems[itemIndex].quantity = newQuantity; this.saveQuoteItems(); this.renderQuoteItems(); } else { this.removeFromQuote(itemIndex); } } // Edit a quote item editQuoteItem(itemIndex) { const item = this.quoteItems[itemIndex]; if (!item) return; // Create edit modal const modal = document.createElement("div"); modal.id = "edit-quote-modal"; modal.className = "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"; modal.innerHTML = `

Edit Quote Item

${
      item.name
    }

${ item.name }

Product ID: ${item.id}

`; document.body.appendChild(modal); // Add form submission handler const form = modal.querySelector("#edit-quote-form"); form.addEventListener("submit", (e) => { e.preventDefault(); this.saveEditChanges(itemIndex); }); // Close modal when clicking outside modal.addEventListener("click", (e) => { if (e.target === modal) { this.closeEditModal(); } }); } // Close edit modal closeEditModal() { const modal = document.getElementById("edit-quote-modal"); if (modal) { modal.remove(); } } // Increment quantity in edit modal incrementEditQuantity() { const input = document.getElementById("edit-quantity"); if (input) { input.value = parseInt(input.value) + 1; } } // Decrement quantity in edit modal decrementEditQuantity() { const input = document.getElementById("edit-quantity"); if (input && parseInt(input.value) > 1) { input.value = parseInt(input.value) - 1; } } // Save changes from edit modal saveEditChanges(itemIndex) { const quantity = parseInt(document.getElementById("edit-quantity").value); const color = document.getElementById("edit-color").value; const size = document.getElementById("edit-size").value; if (quantity < 1) { alert("Quantity must be at least 1"); return; } // Update the item this.quoteItems[itemIndex] = { ...this.quoteItems[itemIndex], quantity: quantity, color: color, size: size, }; this.saveQuoteItems(); this.renderQuoteItems(); this.closeEditModal(); // Show success message this.showEditSuccess(); } // Show success message for edit showEditSuccess() { const notification = document.createElement("div"); notification.className = "fixed top-24 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-x-full"; notification.innerHTML = `
Quote item updated!
`; document.body.appendChild(notification); // Animate in setTimeout(() => { notification.classList.remove("translate-x-full"); }, 100); // Remove after 3 seconds setTimeout(() => { notification.classList.add("translate-x-full"); setTimeout(() => { document.body.removeChild(notification); }, 300); }, 3000); } // Clear all quote items clearQuote() { this.quoteItems = []; this.saveQuoteItems(); this.renderQuoteItems(); } // Get quote items count getQuoteCount() { return this.quoteItems.reduce((total, item) => total + item.quantity, 0); } // Update quote badge in navigation updateQuoteBadge() { const count = this.getQuoteCount(); const quoteLinks = document.querySelectorAll('a[href="quote.html"]'); quoteLinks.forEach((quoteLink) => { // Remove existing badge const existingBadge = quoteLink.querySelector(".quote-badge"); if (existingBadge) { existingBadge.remove(); } // Add new badge if there are items if (count > 0) { const badge = document.createElement("span"); badge.className = "quote-badge absolute -top-2 -right-2 bg-uc-gold text-white text-xs rounded-full w-5 h-5 flex items-center justify-center font-semibold"; badge.textContent = count > 99 ? "99+" : count; quoteLink.style.position = "relative"; quoteLink.appendChild(badge); } }); } // Show success message when item is added showAddToQuoteSuccess() { // Create success notification const notification = document.createElement("div"); notification.className = "fixed top-24 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-x-full"; notification.innerHTML = `
Added to quote!
`; document.body.appendChild(notification); // Animate in setTimeout(() => { notification.classList.remove("translate-x-full"); }, 100); // Remove after 3 seconds setTimeout(() => { notification.classList.add("translate-x-full"); setTimeout(() => { document.body.removeChild(notification); }, 300); }, 3000); } // Render quote items on the quote page renderQuoteItems() { const container = document.getElementById("quote-items-container"); const emptyMessage = document.getElementById("empty-quote-message"); const quoteActions = document.getElementById("quote-actions"); if (!container) return; if (this.quoteItems.length === 0) { // Show empty state if (emptyMessage) emptyMessage.style.display = "block"; if (quoteActions) quoteActions.classList.add("hidden"); // Clear any existing items but keep the empty message const itemsToRemove = container.querySelectorAll(".bg-gray-50"); itemsToRemove.forEach((item) => item.remove()); return; } // Hide empty message and show actions if (emptyMessage) emptyMessage.style.display = "none"; if (quoteActions) quoteActions.classList.remove("hidden"); // Remove any existing items first const itemsToRemove = container.querySelectorAll(".bg-gray-50"); itemsToRemove.forEach((item) => item.remove()); // Render new items this.quoteItems.forEach((item, index) => { const itemElement = document.createElement("div"); itemElement.className = "bg-gray-50 rounded-lg p-6 border border-gray-200"; itemElement.innerHTML = `
${item.name}

${item.name}

Color: ${item.color} Size: ${item.size}
${item.quantity}
`; container.appendChild(itemElement); }); } // Render quote summary in modal renderQuoteSummary() { const summaryContainer = document.getElementById("quote-summary"); if (!summaryContainer) return; summaryContainer.innerHTML = this.quoteItems .map( (item) => `
${item.name}

${item.color} • ${item.size} • Qty: ${item.quantity}

` ) .join(""); } // Initialize quote manager init() { this.updateQuoteBadge(); this.renderQuoteItems(); this.setupEventListeners(); } // Setup event listeners setupEventListeners() { // Clear quote button const clearBtn = document.getElementById("clear-quote-btn"); if (clearBtn) { clearBtn.addEventListener("click", () => { if (confirm("Are you sure you want to clear your quote?")) { this.clearQuote(); } }); } // Request quote button const requestBtn = document.getElementById("request-quote-btn"); if (requestBtn) { requestBtn.addEventListener("click", () => { this.openQuoteModal(); }); } // Modal close button const closeBtn = document.getElementById("close-modal-btn"); if (closeBtn) { closeBtn.addEventListener("click", () => { this.closeQuoteModal(); }); } // Modal backdrop click const modal = document.getElementById("quote-modal"); if (modal) { modal.addEventListener("click", (e) => { if (e.target === modal) { this.closeQuoteModal(); } }); } // Quote form submission const quoteForm = document.getElementById("quote-form"); if (quoteForm) { quoteForm.addEventListener("submit", (e) => { e.preventDefault(); this.submitQuoteRequest(); }); } } // Open quote modal openQuoteModal() { const modal = document.getElementById("quote-modal"); if (modal) { this.renderQuoteSummary(); modal.classList.remove("hidden"); document.body.style.overflow = "hidden"; } } // Close quote modal closeQuoteModal() { const modal = document.getElementById("quote-modal"); if (modal) { modal.classList.add("hidden"); document.body.style.overflow = "auto"; } } // Submit quote request submitQuoteRequest() { const form = document.getElementById("quote-form"); const formData = new FormData(form); // Get form data const quoteData = { name: formData.get("name"), email: formData.get("email"), phone: formData.get("phone"), company: formData.get("company"), project: formData.get("project"), items: this.quoteItems, timestamp: new Date().toISOString(), }; // Here you would typically send this data to your server console.log("Quote request data:", quoteData); // For now, just show success message alert("Thank you for your quote request! We will get back to you soon."); // Clear the quote and close modal this.clearQuote(); this.closeQuoteModal(); // Reset form form.reset(); } } // Global quote manager instance const quoteManager = new QuoteManager(); // Global function to add items to quote (called from other pages) function addToQuote(productData) { quoteManager.addToQuote(productData); } // Initialize when DOM is ready document.addEventListener("DOMContentLoaded", () => { // Quote manager is already initialized in constructor }); // Version: 3.5 - Added edit functionality for quote items