SHOPPING WISH LISTS WITH FIREBASE (PART 2 - Redundant)
I have implemented wish list functionality into my store. Wish list functionality allows users to save and manage a list of desired items or products they may want to purchase in the future. By clicking the heart icon in the category view you can add, or remove products in the wish list individually, and by clicking the button on the cart page, all items in cart are added to the wish list. I use Firebase for this, which I discussed in the previous post. Below you will find a lot of code that handles displaying wished for items on a separate page, however, I just made this code redundant by using a live, or instant approach which filters the shop grid instead. I am keeping the code below for archival purposes only, as it may have a few functions which could be of use later.
HTML:
JAVASCRIPT: <!--WISHLIST DIRECTORY BUTTON IN SHOP--> <div id="wishlistPageButton" class="wishlistPageButton"></div> <script> document.addEventListener('DOMContentLoaded', function() { const subString = 'shop'; const subStringTwo = 'shop/p/'; let getURL = window.location.href; const wishlistPageButton = document.querySelector('.wishlistPageButton'); if (getURL.includes(subString) && !getURL.includes(subStringTwo)) { let isTouch = false; const headerActions = document.querySelector('.header-actions'); function checkHeader() { const styles = window.getComputedStyle(headerActions); isTouch = styles.getPropertyValue('display') !== 'flex'; } checkHeader(); //place the button var nestedCategories = document.querySelector('.nested-category-tree-wrapper'); var categoryList = nestedCategories.querySelector('ul'); categoryList.insertAdjacentElement('afterend', wishlistPageButton); isTouch ? wishlistPageButton.classList.add('mobile') : wishlistPageButton.classList.remove('mobile'); //handle pushing the button wishlistPageButton.addEventListener('click', function(event) { window.location.href = '/wishlist'; }); } else { wishlistPageButton.remove(); } }); </script> <!--WISHLIST PAGE--> <script type="module"> // init firebase import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.12.5/firebase-app.js'; import { getAuth, onAuthStateChanged } from 'https://www.gstatic.com/firebasejs/10.12.5/firebase-auth.js'; import { getFirestore, collection, getDocs, doc, deleteDoc } from 'https://www.gstatic.com/firebasejs/10.12.5/firebase-firestore.js'; const firebaseConfig = {apiKey: "AIzaSyBZSF7gaLoqI5ni_ntvvhujH1kL5h5OaEs", authDomain: "-----------", projectId: "--------", storageBucket: "--------------", messagingSenderId: "-------", appId: "-----------------", measurementId: "--------"}; const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); // The usual page checks document.addEventListener('DOMContentLoaded', () => { const subString = 'wishlist'; const getURL = window.location.href; if (getURL.includes(subString)) { onAuthStateChanged(auth, async (user) => { if (user) { console.log('User authenticated'); // Function to fetch the wishlist item IDs async function fetchWishlistItemIds() { try { const wishlistRef = collection(db, 'users', user.uid, 'wishlist'); const querySnapshot = await getDocs(wishlistRef); const itemIds = querySnapshot.docs.map(doc => doc.id); // Get item IDs return itemIds; } catch (error) { console.error('Error fetching wishlist items:', error); return []; // Return an empty array in case of an error } } // Function to remove an item from the wishlist async function removeItemFromWishlist(itemId, itemElement) { try { const itemRef = doc(db, 'users', user.uid, 'wishlist', itemId); await deleteDoc(itemRef); console.log(`Item ${itemId} removed from wishlist`); // Hide the specific item element instead of reloading itemElement.style.display = 'none'; // Check if all items are removed and display a message if needed const remainingItems = document.querySelectorAll('#product-grid .product-item'); if (remainingItems.length === 0) { const productContent = document.querySelector('.content-wrapper'); if (productContent) { productContent.innerHTML = `<p>None, how despondent!</p>`; productContent.style.display = 'flex'; } } } catch (error) { console.error('Error removing item from wishlist:', error); } } // Function to fetch and display products async function fetchAndDisplayProducts(url) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); // Access the products from the 'items' key const products = data.items; // Get wishlist item IDs const wishlistItemIds = await fetchWishlistItemIds(); // Create a grid container element const gridContainer = document.createElement('div'); gridContainer.id = 'product-grid'; gridContainer.className = 'product-grid'; // Flag to check if any products were added let hasProducts = false; // Generate HTML for each product products.forEach((product) => { if (wishlistItemIds.includes(product.id)) { // Check if product is in wishlist hasProducts = true; let assetUrl = product.assetUrl; if (!assetUrl.includes('images.squarespace')) { if (product.items && product.items.length > 0) { assetUrl = product.items[0].assetUrl; } } const productElement = document.createElement('div'); productElement.className = 'product-item'; productElement.innerHTML = ` <a href="${product.fullUrl}"> <img src="${assetUrl}" alt="${product.name}" class="wishlistItemImage" style="opacity: 1; width: 400px; height: 400px; border: solid 2px black; transition: all 0.3s ease !important;"> <h4 class="wishlistItemTitle" style="cursor: pointer">${product.title}</h4> </a> <button class="remove-from-wishlist sqs-block-button-element--medium sqs-button-element--primary sqs-block-button-element sqs-block-button-container" style="text-align: right" data-product-id="${product.id}">Discard</button> `; // Append the product element to the grid container gridContainer.appendChild(productElement); } }); const productSection = document.querySelector('[data-section-id="66bbf4f37d8e3666c9d71b7b"]'); const productContent = productSection.querySelector('.content-wrapper'); if (productContent) { productContent.innerHTML = ''; // Clear any existing content if (hasProducts) { productContent.appendChild(gridContainer); } else { productContent.innerHTML = `<p>None, how despondent!</p>`; productContent.style.display = 'flex'; } // Add event listeners to remove buttons document.querySelectorAll('.remove-from-wishlist').forEach(button => { button.addEventListener('click', (event) => { event.preventDefault(); // Prevent default action if inside a link const itemId = button.getAttribute('data-product-id'); const itemElement = button.closest('.product-item'); // Get the product item element removeItemFromWishlist(itemId, itemElement); }); }); } } catch (error) { console.error('Error fetching the products:', error); const productSection = document.querySelector('[data-section-id="66bbf4f37d8e3666c9d71b7b"]'); const productContent = productSection.querySelector('.content-wrapper'); if (productContent) { productContent.innerHTML = `<p>None, how despondent!</p>`; productContent.style.display = 'flex'; } } } const productsUrl = 'https://www.polivantage.com/shop?format=json-pretty'; fetchAndDisplayProducts(productsUrl); } else { console.error('User not authenticated'); window.location.href = '/login'; } }); } }); </script>
CSS: section[data-section-id="66bbf4f37d8e3666c9d71b7b"] .content-wrapper .content { width: 0 !important; } .product-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 25px; } @media only screen and (max-width:790px) { .product-grid { grid-template-columns: repeat(1, 1fr); } } .product-item { margin-bottom: 40px; transition: all 0.3s ease; } .product-item:hover .wishlistItemImage { transform: scale(1.05); } .wishlistItemTitle { margin: 0; margin-bottom: 20px; margin-top: 10px; text-align: center; word-wrap: break-word; overflow-wrap: break-word; max-width: 100%; } .wishlistItemImage { margin: 0; transition: all 0.3s ease; } .remove-from-wishlist { width: 100%; text-align: right; } //wishlist category button #wishlistPageButton { background-image: url('https://images.squarespace-cdn.com/content/v1/6654b2fee26f292de13f1a9d/d88a683e-1625-4ab8-87f8-69467233fa6b/heartGrabbedicon.png'); width: 60px !important; height: 60px !important; margin-top: -15px; pointer-events: auto; cursor: pointer; background-repeat: no-repeat; background-position: center; background-size: contain; transition: all 0.6s ease; scale: 1; } #wishlistPageButton.mobile { margin-left: 160px; margin-bottom: 20px; } #wishlistPageButton:hover { transition: all 0.3s ease; scale: 1.15; }
COMMENTS:
Leave a comment: