From 9b79a380a8907813eecbd85e68599c07461f7ca5 Mon Sep 17 00:00:00 2001 From: Tim Adams <zfac125@live.rhul.ac.uk> Date: Sun, 24 Mar 2024 23:39:38 +0000 Subject: [PATCH] search function and checkout is done but these are running with some issues. --- controllers/pagesCtrlFile.js | 3 + public/cart.js | 58 +++++++++++ public/checkout.js | 21 ++++ public/main-search.js | 185 +++++++++++++++++++++++++++++++++++ public/product-cards.js | 21 ---- public/search.js | 11 +-- public/slides.js | 27 +---- public/style.css | 22 +++++ routes/pages.js | 3 +- views/cart.hbs | 74 ++++++++++---- views/checkout.hbs | 91 +++++++++++++++++ views/index.hbs | 4 +- views/kids-shoes.hbs | 7 +- views/kids.hbs | 2 +- views/men-shoes.hbs | 2 +- views/men.hbs | 2 +- views/women-shoes.hbs | 2 +- views/women.hbs | 2 +- 18 files changed, 450 insertions(+), 87 deletions(-) create mode 100644 public/cart.js create mode 100644 public/checkout.js create mode 100644 public/main-search.js delete mode 100644 public/product-cards.js create mode 100644 views/checkout.hbs diff --git a/controllers/pagesCtrlFile.js b/controllers/pagesCtrlFile.js index 022eb0b..7ea8cb8 100644 --- a/controllers/pagesCtrlFile.js +++ b/controllers/pagesCtrlFile.js @@ -39,3 +39,6 @@ exports.activateAccountCtrlFunction = (req, res) => { res.render('activate'); } +exports.checkouttCtrlFunction = (req, res) => { + res.render('checkout'); +} diff --git a/public/cart.js b/public/cart.js new file mode 100644 index 0000000..59b0805 --- /dev/null +++ b/public/cart.js @@ -0,0 +1,58 @@ +document.querySelector('.search-bar').style.display = 'none'; + +const table = document.querySelector('table') +table.innerHTML =` + <tr> + <th>Product</th> + <th>Image</th> + <th>Price per unit</th> + <th>Amount</th> + <th>Total Price</th> + </tr> +` + +let shoppingCardItems = JSON.parse(localStorage.getItem('shoppingCardItems')) || [] + +let idItemMap = {} + +shoppingCardItems.forEach(item => { + if (!idItemMap[item.id]) idItemMap[item.id]= []; + idItemMap[item.id].push(item) +}) + +const uniqueEntries = [] + +Object.values(idItemMap).forEach(arr => { + uniqueEntries.push(arr[0]) +}) + +let totalCost = 0 +uniqueEntries.forEach(item => { + table.innerHTML +=` +<tr> + <td>${item.name}</td> + <td><img src="${item.image}" height="70" width="70"/></td> + <td>${item.price}</td> + <td>${idItemMap[item.id].length}</td> + <td>${idItemMap[item.id].length * item.price}</td> +</tr> + ` + totalCost += idItemMap[item.id].length * item.price +}) + +table.innerHTML +=` +<tr> + <td></td> + <td></td> + <td></td> + <td></td> + <td><strong>Total cost: ${totalCost}</strong></td> +</tr>` + +localStorage.setItem('totalCost', totalCost) + +function handleProceedCheckout(){ + window.location.href="/checkout" +} + + diff --git a/public/checkout.js b/public/checkout.js new file mode 100644 index 0000000..ea2c056 --- /dev/null +++ b/public/checkout.js @@ -0,0 +1,21 @@ +document.querySelector('.search-bar').style.display = 'none'; + + +const i = document.querySelectorAll('input'); +i.forEach(el => el.addEventListener('keyup', checkComplete)) + + +function checkComplete() { + let isComplete = true + i.forEach((el, ind) => { + if (!ind) return; + if (!el.value.trim()) isComplete = false; + }) + console.log({isComplete}) + + if (isComplete) { + document.querySelector('.buy-now button').disabled = false; + document.querySelector('.g-warning').innerText = ""; + + } +} \ No newline at end of file diff --git a/public/main-search.js b/public/main-search.js new file mode 100644 index 0000000..8a03fb1 --- /dev/null +++ b/public/main-search.js @@ -0,0 +1,185 @@ +function debounce(callback, delay) { + let timerId; + return function(...args) { + clearTimeout(timerId); + return new Promise(resolve => { + timerId = setTimeout(() => { + resolve(callback(...args)); + }, delay); + }); + }; +} + +const urlObj = new URL(window.location.href); +const path = urlObj.pathname; + +let selector = path.split("/")[1] ? '.container' :'.car-con' + +const container = document.querySelector(selector).innerHTML; + + +const debouncedHandleSearchChangeAsync = debounce(fetchAndPopulateProducts, 300); + +document.getElementById('search-input').addEventListener('keyup', () => { + debouncedHandleSearchChangeAsync(); +}); + +async function fetchAndPopulateProducts() { + const query = document.getElementById('search-input').value + + if (query.trim() === "" && !path.split("/")[1]) { + document.querySelector(selector).innerHTML = container; + return; + } + + const mapping = { + men:'men', + women:'women', + kids:'kids', + 'kids-shoes':'K-shoes', + 'men-shoes':'M-shoes', + 'women-shoes':'W-shoes', + } + const url = `http://localhost:7000/products?q=${query}&cat=${mapping[path.split("/")[1]] ?? ""}` + + const response = await fetch(url); + if (!response.ok) { + alert('Could not search for products') + throw new Error(`HTTP error! Status: ${response.status}`); + } + + const products = await response.json() + + populateProducts(products) +} + +function populateProducts(products) { + const container = document.querySelector(selector); + container.style.flexDirection = 'row'; + container.style.flexWrap = 'wrap' + container.style.justifyContent = 'center' + + try { + container.innerHTML = ''; + + products.forEach(product => { + const productsHtml = document.createElement('div'); + productsHtml.innerHTML = ` + <div class="product"> + <div class="product-card"> + <h2 class="name">${product.name}</h2> + <span class="price">£${product.price}</span> + <a class="popup-btn">Quick View</a> + <img src="${product.image}" class="product-img" alt="Image of ${product.name}"> + </div> + <div class="popup-view"> + <div class="popup-card"> + <a><i class="fas fa-times close-btn"></i></a> + <div class="product-img"> + <img src="${product.image}" class="product-img" alt="Image of ${product.name}"> + </div> + <div class="info"> + <h2>Your fashion<br><span>Modern styles</span></h2> + <p>${product.description}</p> + <span class="price">£${product.price}</span> + <a href="#" class="add-cart-btn">Add to Cart</a> + <a href="#" class="add-wish">Add to Wishlist</a> + </div> + </div> + </div> + </div> + `; + container.appendChild(productsHtml); + + if (products.image) { + const img = new Image(); + img.src = `data:image/jpeg;base64,${product.image.toString('base64')}`; + productsHtml.appendChild(img); + } + if(container){ + container.appendChild(productsHtml); + }else{ + console.error('Container element not found'); + } + }); + } catch (error) { + console.error('Failed to populate products:', error); + } + addCartActions(products); +} + + +function addCartActions(products) { + + var popupViews = document.querySelectorAll('.popup-view'); + var popupBtns = document.querySelectorAll('.popup-btn'); + var closeBtns = document.querySelectorAll('.close-btn'); + //javascript for quick view button + var popup = function (popupClick) { + popupViews[popupClick].classList.add('active'); + } + popupBtns.forEach((popupBtn, i) => { + popupBtn.addEventListener("click", () => { + popup(i); + }); + }); + //javascript for close button + closeBtns.forEach((closeBtn) => { + closeBtn.addEventListener("click", () => { + popupViews.forEach((popupView) => { + popupView.classList.remove('active'); + }); + }); + }); + const carts = document.querySelectorAll('.add-cart-btn'); + + for (let i = 0; i < carts.length; i++) { + + carts[i].addEventListener('click', () => { + cardsNumbers(products[i]); + }); + } +} + + +async function cardsNumbers(product) { + const loggedInuser = JSON.parse(localStorage.getItem('user')) + if (!loggedInuser) { + updateShoppingCart(product) + return + } + + try { + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + userId: loggedInuser.id, + productId: product.id + }) + }; + + const url = `http://localhost:7000/shopping-cart` + + const response = await fetch(url, options); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + updateShoppingCart(product) + + } catch (error) { + console.error(error); + } + +} + +function updateShoppingCart(product){ + const shoppingCardItems = JSON.parse(localStorage.getItem('shoppingCardItems')) || [] + shoppingCardItems.push(product) + + localStorage.setItem('shoppingCardItems', JSON.stringify(shoppingCardItems)) + document.querySelector('.add-cart span').textContent = shoppingCardItems.length; +} \ No newline at end of file diff --git a/public/product-cards.js b/public/product-cards.js deleted file mode 100644 index 4cbf388..0000000 --- a/public/product-cards.js +++ /dev/null @@ -1,21 +0,0 @@ - -/* var popupViews = document.querySelectorAll('.popup-view'); -var popupBtns = document.querySelectorAll('.popup-btn'); -var closeBtns = document.querySelectorAll('.close-btn'); -//javascript for quick view button -var popup = function(popupClick) { - popupViews[popupClick].classList.add('active'); -} -popupBtns.forEach((popupBtn, i) => { - popupBtn.addEventListener("click", () => { - popup(i); - }); -}); -//javascript for close button -closeBtns.forEach((closeBtn) => { - closeBtn.addEventListener("click", () => { - popupViews.forEach((popupView) => { - popupView.classList.remove('active'); - }); - }); -}); */ \ No newline at end of file diff --git a/public/search.js b/public/search.js index 815f74d..e19f0b9 100644 --- a/public/search.js +++ b/public/search.js @@ -1,6 +1,4 @@ -/* let products1 = []; - -const searchBar = document.getElementById('search-input'); +let products1 = []; @@ -53,9 +51,7 @@ const loadProducts = async () => { } const data = await res.json(); - console.log(data); // To check the structure of the fetched data products1 = Array.isArray(data) ? data : []; - console.log('Products after fetching:', products1); displayCarts(products1); initializeSearch(); } catch (err) { @@ -81,8 +77,3 @@ function initializeSearch() { }); } -document.addEventListener('DOMContentLoaded', () => { - loadProducts(); -}); - - */ \ No newline at end of file diff --git a/public/slides.js b/public/slides.js index c60e5fc..0ce60d3 100644 --- a/public/slides.js +++ b/public/slides.js @@ -1,22 +1,4 @@ -/*let slideIndex = 0; -showSlides(); - -function showSlides() { - let i; - let slides = document.getElementsByClassName("mySlides"); - let dots = document.getElementsByClassName("dot"); - for (i = 0; i < slides.length; i++) { - slides[i].style.display = "none"; - } - slideIndex++; - if (slideIndex > slides.length) {slideIndex = 1} - for (i = 0; i < dots.length; i++) { - dots[i].className = dots[i].className.replace(" active", ""); - } - slides[slideIndex-1].style.display = "block"; - dots[slideIndex-1].className += " active"; - setTimeout(showSlides, 2000); // Change image every 2 seconds -}*/ + var carousel = document.querySelector('.carousel'); var cellCount = 9; @@ -24,25 +6,24 @@ var selectedIndex = 0; function rotateCarousel() { var angle = selectedIndex / cellCount * -360; - carousel.style.transform = 'translateZ(-288px) rotateY(' + angle + 'deg)'; + carousel.style.transform = 'translateZ(-588px) rotateY(' + angle + 'deg)'; } var prevButton = document.querySelector('.previous-button'); prevButton.addEventListener( 'click', function() { - selectedIndex--; + selectedIndex++; rotateCarousel(); }); var nextButton = document.querySelector('.next-button'); nextButton.addEventListener( 'click', function() { - selectedIndex++; + selectedIndex--; rotateCarousel(); }); let isDragging = false; let initialX; -//const carousel = document.getElementById('carousel'); carousel.addEventListener('touchstart', (e) => { isDragging = true; diff --git a/public/style.css b/public/style.css index f6b1dbf..b7a46fb 100644 --- a/public/style.css +++ b/public/style.css @@ -163,6 +163,28 @@ header{ margin-top: 50px; } +/*-------------register form--------------*/ +.authenticate-form { + display:block; + justify-content: center; + padding: 240px 90px 24px 90px; + +} + +.input-group{ + width: 100%; + min-width: 300px; + padding: 12px 24px; + border-radius: 24px; + font-size: 16px; + border: 0px; + outline: none; +} + +.btn{ + margin-left: 40px; +} + /*Styles for product card*/ .product .product-card { diff --git a/routes/pages.js b/routes/pages.js index ed2dafb..b3c4bd4 100644 --- a/routes/pages.js +++ b/routes/pages.js @@ -1,7 +1,7 @@ const express = require('express'); const { hCtrlFunction, cartCtrlFunction, kidsSCtrlFunction, kidsCtrlFunction, menSCtrlFunction, menCtrlFunction, - womenSCtrlFunction, womenCtrlFunction, authenticateCtrlFunction, activateAccountCtrlFunction } = require('../controllers/pagesCtrlFile'); + womenSCtrlFunction, womenCtrlFunction, authenticateCtrlFunction, activateAccountCtrlFunction, checkouttCtrlFunction } = require('../controllers/pagesCtrlFile'); const router = express.Router(); @@ -16,5 +16,6 @@ router.get('/women', womenCtrlFunction); router.get('/', hCtrlFunction); router.get('/authenticate', authenticateCtrlFunction); router.get('/activate-account', activateAccountCtrlFunction); +router.get('/checkout', checkouttCtrlFunction); module.exports = router; \ No newline at end of file diff --git a/views/cart.hbs b/views/cart.hbs index 2bd10c9..78efcfb 100644 --- a/views/cart.hbs +++ b/views/cart.hbs @@ -13,9 +13,43 @@ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="/style.css"> - <script src="/shopping-basket.js" async></script> - <script src="/payment.js"></script> + <style> + .cart-container { + margin: 2%; + border: 2px dashed #333; + border-radius: 4%; + padding: 2%; + } + .cart-header { + background-color: #aaa; + padding: 1%; + border-radius: 3px; + } + .cart-header h2 { + text-align: center; + color: #0b1544; + } + table { + width: 100%; + } + table tr td, th { + text-align: center; + } + th, td { + padding: 4px; + } + + .prod-container { + margin: 400px auto; + margin-bottom:0px; + } + + .checkout-container { + text-align: center; + margin-bottom:23px; + } + </style> @@ -30,25 +64,27 @@ </header> - <div class="prods-container"> - <div class="prod-header"> - <h5 class="prod-title">PRODUCT</h5> - <h5 class="price">PRICE</h5> - <h5 class="quantity">QUANTITY</h5> - <h5 class="total">TOTAL</h5> - </div> - <div class="prods"></div> - <div id="container"></div> - </div> - <div id="buy-now">Buy Now</div> - + <div class="prod-container"> + <div class="cart-container"> + <div class="cart-header"> + <h2> You items</h2> + </div> + <div class="cart-content"> + <table border="1"> + </table> + </div> + </div> + <div class="checkout-container"> + <button class="btn btn-primary" onclick="handleProceedCheckout()">Proceed to Checkout</button> + </div> + {{!-- <div id="buy-now">Buy Now</div> --}} - <script async - src="https://pay.google.com/gp/p/js/pay.js" - onload="onGooglePayLoaded()"></script> - <script src="/search.js"></script> + + {{!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.7/axios.min.js" integrity="sha512-NQfB/bDaB8kaSXF8E77JjhHG5PM6XVRxvHzkZiwl3ddWCEPBa23T76MuWSwAJdMGJnmQqM0VeY9kFszsrBEFrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> --}} + {{!-- <script async src="https://pay.google.com/gp/p/js/pay.js" onload="onGooglePayLoaded()"></script> --}} + <script src="/cart.js"></script> </body> - {{> common/footer}} + {{> common/footer}} </html> \ No newline at end of file diff --git a/views/checkout.hbs b/views/checkout.hbs new file mode 100644 index 0000000..e7d96fa --- /dev/null +++ b/views/checkout.hbs @@ -0,0 +1,91 @@ +<!DOCTYPE html> + +<html lang="en" charset="UTF-8"> + +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> + <title>Your Fashion</title> + + <link rel="preconnect" href="https://fonts.gstatic.com"> + + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> + <link rel="stylesheet" href="/style.css"> + <style> + .prod-container1 { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + margin: 200 auto; + margin-bottom: 50px; + margin-top: 100px; + } + + .form-group { + width: 500px; + } + + .buy-now { + display: flex; + justify-content: center; + position: relative + } + </style> + + + + +</head> + +<body class="responsive"> + + + <header> + {{> common/navbar}} + + </header> + + <div class="prod-container1"> + <div class="form-group"> + <label for="name">Full name *</label> + <input type="text" class="form-control" id="name" placeholder="Enter your full name" required> + </div> + <div class="form-group"> + <label for="address">Address *</label> + <input type="text" class="form-control" id="Address" placeholder="Enter your address" required> + </div> + <div class="form-group"> + <label for="city">City *</label> + <input type="text" class="form-control" id="City" placeholder="Enter your city" required> + </div> + <div class="form-group"> + <label for="city">Post-code *</label> + <input type="text" class="form-control" id="PostCode" placeholder="Enter your post code" required> + </div> + <div class="form-group"> + <label for="pnumber">Phone Number</label> + <input type="text" class="form-control" id="pNumber" placeholder="Enter your phone number"> + </div> + <br> + <div class="buy-now"> + <div id="buy-now">Buy Now</div> + </div> + </div> + + <p class="g-warning" style="text-align:center;color:orange"></p> + + + <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.7/axios.min.js" + integrity="sha512-NQfB/bDaB8kaSXF8E77JjhHG5PM6XVRxvHzkZiwl3ddWCEPBa23T76MuWSwAJdMGJnmQqM0VeY9kFszsrBEFrQ==" + crossorigin="anonymous" referrerpolicy="no-referrer"></script> + <script async src="https://pay.google.com/gp/p/js/pay.js" onload="onGooglePayLoaded()"></script> + <script src="/checkout.js"></script> + <script src="/payment.js"></script> + +</body> + +</html> \ No newline at end of file diff --git a/views/index.hbs b/views/index.hbs index 17501d9..d972be7 100644 --- a/views/index.hbs +++ b/views/index.hbs @@ -14,8 +14,6 @@ - <!--<script type="text/javascript" src="js/LocalLogin.js"></script>--> - </head> <body class="responsive"> @@ -67,7 +65,7 @@ <script src="/slides.js"></script> - <script src="/search.js"></script> + <script src="/main-search.js"></script> <script src="/shopping-basket.js"></script> </body> diff --git a/views/kids-shoes.hbs b/views/kids-shoes.hbs index 33b70c2..88f2a16 100644 --- a/views/kids-shoes.hbs +++ b/views/kids-shoes.hbs @@ -32,13 +32,10 @@ <div class="container" id="container"></div> {{> common/footer}} - <script src="/search.js" type="module"></script> + <script src="/main-search.js" type="module"></script> <script src="/shopping-basket.js"></script> </body> -<footer> - <p>Author: Tim Adams<br><a href="mailto:tim.adams1@hotmail.com">tim.adams1@hotmail.com</a><br><a>☎ - 07469241247</a></p> -</footer> + </html> \ No newline at end of file diff --git a/views/kids.hbs b/views/kids.hbs index ed1a089..9e1ffbe 100644 --- a/views/kids.hbs +++ b/views/kids.hbs @@ -32,7 +32,7 @@ <div class="container" id="container"></div> {{> common/footer}} - <script src="/search.js" type="module"></script> + <script src="/main-search.js"></script> <script src="/shopping-basket.js"></script> </body> diff --git a/views/men-shoes.hbs b/views/men-shoes.hbs index c1a53d6..f1424cb 100644 --- a/views/men-shoes.hbs +++ b/views/men-shoes.hbs @@ -32,7 +32,7 @@ <div class="container" id="container"></div> {{> common/footer}} - <script src="/search.js" type="module"></script> + <script src="/main-search.js" type="module"></script> <script src="/shopping-basket.js"></script> </body> diff --git a/views/men.hbs b/views/men.hbs index 7dd82d0..9e353d3 100644 --- a/views/men.hbs +++ b/views/men.hbs @@ -38,7 +38,7 @@ <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.7/axios.min.js" integrity="sha512-NQfB/bDaB8kaSXF8E77JjhHG5PM6XVRxvHzkZiwl3ddWCEPBa23T76MuWSwAJdMGJnmQqM0VeY9kFszsrBEFrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> --}} - <script src="/search.js" type="module"></script> + <script src="/main-search.js" type="module"></script> <script src="/shopping-basket.js"></script> diff --git a/views/women-shoes.hbs b/views/women-shoes.hbs index ed1a089..9e1ffbe 100644 --- a/views/women-shoes.hbs +++ b/views/women-shoes.hbs @@ -32,7 +32,7 @@ <div class="container" id="container"></div> {{> common/footer}} - <script src="/search.js" type="module"></script> + <script src="/main-search.js"></script> <script src="/shopping-basket.js"></script> </body> diff --git a/views/women.hbs b/views/women.hbs index bc171ee..2c0d07c 100644 --- a/views/women.hbs +++ b/views/women.hbs @@ -33,7 +33,7 @@ {{> common/footer}} - <script src="/search.js" type="module"></script> + <script src="/main-search.js" type="module"></script> <script src="/shopping-basket.js"></script> </body> -- GitLab