From 87cc21d9c655da07e79c3452092637db9f61a095 Mon Sep 17 00:00:00 2001 From: Ben <36240171+benkyd@users.noreply.github.com> Date: Tue, 26 Apr 2022 17:42:57 +0100 Subject: [PATCH] ampersand search query bug fix Former-commit-id: 5b72eeabea7458d1bcbc13f9642b39350b1b3267 --- client/public/components/basket.mjs | 182 ++++++++++++++++-- client/public/components/product-listing.mjs | 3 +- client/public/components/search.mjs | 8 +- .../components/super-compact-listing.mjs | 9 +- client/public/components/tag.mjs | 2 +- .../public/components/templates/navbar.html | 2 +- client/public/search/index.html | 4 +- src/controllers/controller-master.js | 2 +- src/routes/helpers.js | 7 + 9 files changed, 193 insertions(+), 26 deletions(-) diff --git a/client/public/components/basket.mjs b/client/public/components/basket.mjs index 25de764..3b473f2 100644 --- a/client/public/components/basket.mjs +++ b/client/public/components/basket.mjs @@ -14,35 +14,189 @@ class Basket extends Component { this.setState({ ...basketItems, }, false); - console.log(basketItems, this.state); + } else { + this.setState({ + items: {}, + total: 0, + }, false); } - } Render() { return { template: /* html */` - {this.state.name} +
+
+
+ Your Basket +
+
+ Total: {this.state.total} items +
+
+
+
+ ${Object.keys(this.state.items).map((key) => { + const item = this.state.items[key]; + console.log(key, item); + const modifier = key.includes('~'); + return /* html */` +
+ + +
+ + + +  0 in stock +
+ +
+ `; + }).join('')} +
+
`, style: ` - .tag { - font-size: 0.8em; - padding: 0.2em 0.5em; - margin-right: 0.3em; - margin-top: 0.2em; - margin-bottom: 0.2em; - line-height: 1.3em; - font-weight: bold; - background-color: #F2CA52; + .basket { + padding-top: 10px; + } + + .basket-header { + display: flex; + font-size: 2em; + justify-content: space-between; + align-items: center; + padding: 10px; + border-bottom: 1px solid #ccc; + } + + .basket-item { + display: flex; + flex-direction: row; + align-items: center; + } + + .basket-item-listing { + width: 100%; + margin: 0 auto; + font-size: 1.3em; + } + + .product-quantity-selector { + flex-basis: 40%; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + font-size: 1em; + } + + .product-quantity-button { cursor: pointer; + font-size: 1.7em; + border: #1A1A1A solid 1px; + background-color: #F5F6F6; + border-radius: 0.2em; + width: 1.5em; + height: 1.5em; + } + + .remove-quantity { + font-size: 1em; + width: fit-content; + } + + /* https://www.w3schools.com/howto/howto_css_hide_arrow_number.asp */ + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + input[type=number] { + -moz-appearance: textfield; + } + + .quantity-input { + height: 2.2em; + width: 3.7em; + background-color: #F5F6F6; + border-top: #1A1A1A solid 1px; + border-bottom: #1A1A1A solid 1px; + border-right: none; + border-left: none; + text-align: center; + font-size: 1.2em; } `, }; } OnRender() { - this.root.addEventListener('click', () => { - this.root.classList.toggle('tag-selected'); + this.root.querySelectorAll('.basket-item-listing').forEach((listing) => { + // listen to mutations on the attribute stock because the stock is updated once the + // super compact listing is loaded and the stock is updated + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.attributeName === 'stock') { + const stock = parseInt(mutation.target.getAttribute('stock')); + + // update the stock number + const stockNumber = mutation.target.parentElement.querySelector('.stock-number'); + stockNumber.innerText = stock; + const stockMax = mutation.target.parentElement.querySelector('.quantity-input'); + stockMax.setAttribute('max', stock); + } + }); + }); + observer.observe(listing, { + attributes: true, + attributeFilter: ['stock'], + }); + }); + + // set up each button to update the quantity and remove if it is zero + this.root.querySelectorAll('.product-quantity-button').forEach((button) => { + button.addEventListener('click', (event) => { + const item = event.target.parentElement.parentElement; + const id = item.getAttribute('id'); + const type = item.getAttribute('type'); + const modifier = item.getAttribute('modifier'); + const quantity = parseInt(item.querySelector('.quantity-input').value); + const stock = parseInt(item.querySelector('.stock-number').innerText); + + // update the quantity + if (event.target.classList.contains('reduce-quantity')) { + if (quantity > 0) { + item.querySelector('.quantity-input').value = quantity - 1; + } + } else if (event.target.classList.contains('increase-quantity')) { + if (quantity < stock) { + item.querySelector('.quantity-input').value = quantity + 1; + } + } else if (event.target.classList.contains('remove-quantity')) { + // remove the item from the basket + // delete this.state.items[id]; + // this.setState({ + // items: this.state.items, + // }, true); + } + + // update the total + this.setState({ + total: Object.keys(this.state.items).reduce((total, key) => { + const item = this.state.items[key]; + return total + (item.quantity * item.price); + }, 0), + }, true); + + // update the basket in local storage + // localStorage.setItem('basket', JSON.stringify(this.state)); + }); }); } } diff --git a/client/public/components/product-listing.mjs b/client/public/components/product-listing.mjs index 1254470..5b8e46d 100644 --- a/client/public/components/product-listing.mjs +++ b/client/public/components/product-listing.mjs @@ -111,8 +111,7 @@ class ProductListing extends Component {
`; } - - console.log(this.state); + return { template: /* html */`
diff --git a/client/public/components/search.mjs b/client/public/components/search.mjs index c885dc5..ec1dd37 100644 --- a/client/public/components/search.mjs +++ b/client/public/components/search.mjs @@ -118,6 +118,8 @@ class Search extends Component { return; } + value = encodeURIComponent(value); + const route = `/api/search?q=${value}&per_page=10`; fetch(route).then((response) => { return response.json(); @@ -148,8 +150,10 @@ class Search extends Component { if (e.keyCode === 13) { const searchTerm = e.target.value; - if (searchTerm.length > 0) { - window.location.href = `/search?q=${searchTerm}`; + const encodedSearchTerm = encodeURIComponent(searchTerm); + + if (encodedSearchTerm.length > 0) { + window.location.href = `/search?q=${encodedSearchTerm}`; } } }); diff --git a/client/public/components/super-compact-listing.mjs b/client/public/components/super-compact-listing.mjs index e915e68..cf5b5fb 100644 --- a/client/public/components/super-compact-listing.mjs +++ b/client/public/components/super-compact-listing.mjs @@ -1,7 +1,6 @@ import { RegisterComponent, Component } from './components.mjs'; // super compact listing is interoperable through types which makes it exteremeely poggers and also portable - class SuperCompactProductListing extends Component { static __IDENTIFY() { return 'super-compact-listing'; } @@ -18,6 +17,8 @@ class SuperCompactProductListing extends Component { const tags = product.tags; const colours = product.colours; + this.setAttribute('stock', product.stock); + this.setState({ ...this.getState, name, @@ -53,7 +54,7 @@ class SuperCompactProductListing extends Component { Image of {this.state.name} + src="/api/cdn/${this.state.id}${this.state.bigimage ? '' : '-thumb'}.png"> ${modifierPreview} @@ -61,7 +62,7 @@ class SuperCompactProductListing extends Component {
${this.state.modifier ? `Colour: ${this.state.colours[this.state.modifier].name}` : ''}
${this.state.tags - ? this.state.tags.map(tag => ``).join('') + ? this.state.tags.map(tag => ``).join('') : ``}
@@ -108,6 +109,8 @@ class SuperCompactProductListing extends Component { } .product-image { + max-height: 150px; + max-width: 150px; object-fit: scale-down; object-position: center; } diff --git a/client/public/components/tag.mjs b/client/public/components/tag.mjs index 6239552..380fb31 100644 --- a/client/public/components/tag.mjs +++ b/client/public/components/tag.mjs @@ -30,7 +30,7 @@ class Tag extends Component { OnRender() { this.root.addEventListener('click', () => { - this.root.classList.toggle('tag-selected'); + window.location.href = `/search?q=${this.state.name}`; }); } } diff --git a/client/public/components/templates/navbar.html b/client/public/components/templates/navbar.html index e0ff304..a47e68e 100644 --- a/client/public/components/templates/navbar.html +++ b/client/public/components/templates/navbar.html @@ -27,7 +27,7 @@