diff --git a/.eslintcache b/.eslintcache deleted file mode 100644 index cd006ada..00000000 --- a/.eslintcache +++ /dev/null @@ -1 +0,0 @@ -[{"/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/common/hooks/faceted-search.js":"1","/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/common/faceted-search.js":"2","/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/custom/category-filters.js":"3","/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/common/carousel.js":"4","/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/common/swiper-carousel/index.js":"5"},{"size":754,"mtime":1707849697163,"results":"6","hashOfConfig":"7"},{"size":15986,"mtime":1707835370540,"results":"8","hashOfConfig":"7"},{"size":1062,"mtime":1707834649422,"results":"9","hashOfConfig":"7"},{"size":2785,"mtime":1708944127430,"results":"10","hashOfConfig":"11"},{"size":2190,"mtime":1708944127430,"results":"12","hashOfConfig":"11"},{"filePath":"13","messages":"14","suppressedMessages":"15","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1gd3vyx",{"filePath":"16","messages":"17","suppressedMessages":"18","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19","messages":"20","suppressedMessages":"21","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22","messages":"23","suppressedMessages":"24","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1hal5ky",{"filePath":"25","messages":"26","suppressedMessages":"27","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/common/hooks/faceted-search.js",[],[],"/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/common/faceted-search.js",[],["28","29"],"/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/custom/category-filters.js",[],[],"/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/common/carousel.js",[],["30","31","32","33","34","35","36"],"/Users/martibelegu/Documents/Xfive/xcorner/assets/js/theme/common/swiper-carousel/index.js",[],["37","38","39","40"],{"ruleId":"41","severity":2,"message":"42","line":236,"column":17,"nodeType":"43","messageId":"44","endLine":236,"endColumn":25,"suppressions":"45"},{"ruleId":"41","severity":2,"message":"42","line":238,"column":17,"nodeType":"43","messageId":"44","endLine":238,"endColumn":25,"suppressions":"46"},{"ruleId":"47","severity":2,"message":"48","line":5,"column":8,"nodeType":"49","endLine":5,"endColumn":21,"suppressions":"50"},{"ruleId":"47","severity":2,"message":"51","line":6,"column":8,"nodeType":"49","endLine":6,"endColumn":32,"suppressions":"52"},{"ruleId":"47","severity":2,"message":"53","line":7,"column":8,"nodeType":"49","endLine":7,"endColumn":31,"suppressions":"54"},{"ruleId":"55","severity":2,"message":"56","line":34,"column":9,"nodeType":"57","messageId":"58","endLine":34,"endColumn":58,"suppressions":"59"},{"ruleId":"55","severity":2,"message":"56","line":92,"column":9,"nodeType":"57","messageId":"58","endLine":92,"endColumn":58,"suppressions":"60"},{"ruleId":"55","severity":2,"message":"56","line":96,"column":9,"nodeType":"57","messageId":"58","endLine":96,"endColumn":53,"suppressions":"61"},{"ruleId":"55","severity":2,"message":"56","line":100,"column":9,"nodeType":"57","messageId":"58","endLine":100,"endColumn":64,"suppressions":"62"},{"ruleId":"47","severity":2,"message":"48","line":5,"column":8,"nodeType":"49","endLine":5,"endColumn":21,"suppressions":"63"},{"ruleId":"47","severity":2,"message":"51","line":6,"column":8,"nodeType":"49","endLine":6,"endColumn":32,"suppressions":"64"},{"ruleId":"47","severity":2,"message":"53","line":7,"column":8,"nodeType":"49","endLine":7,"endColumn":31,"suppressions":"65"},{"ruleId":"47","severity":2,"message":"66","line":8,"column":8,"nodeType":"49","endLine":8,"endColumn":25,"suppressions":"67"},"no-param-reassign","Assignment to property of function parameter '$element'.","Identifier","assignmentToFunctionParamProp",["68"],["69"],"import/no-unresolved","Unable to resolve path to module 'swiper/scss'.","Literal",["70"],"Unable to resolve path to module 'swiper/scss/navigation'.",["71"],"Unable to resolve path to module 'swiper/css/pagination'.",["72"],"no-new","Do not use 'new' for side effects.","ExpressionStatement","noNewStatement",["73"],["74"],["75"],["76"],["77"],["78"],["79"],"Unable to resolve path to module 'swiper/css/grid'.",["80"],{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},{"kind":"81","justification":"82"},"directive",""] \ No newline at end of file diff --git a/assets/icons/decrease-quantity.svg b/assets/icons/decrease-quantity.svg new file mode 100644 index 00000000..a3b8095b --- /dev/null +++ b/assets/icons/decrease-quantity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/increase-quantity.svg b/assets/icons/increase-quantity.svg new file mode 100644 index 00000000..f48a512d --- /dev/null +++ b/assets/icons/increase-quantity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/star-filled.svg b/assets/icons/star-filled.svg new file mode 100644 index 00000000..06dba74d --- /dev/null +++ b/assets/icons/star-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/star-unfilled.svg b/assets/icons/star-unfilled.svg new file mode 100644 index 00000000..271f39a5 --- /dev/null +++ b/assets/icons/star-unfilled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/trash.svg b/assets/icons/trash.svg new file mode 100644 index 00000000..1a5f51f4 --- /dev/null +++ b/assets/icons/trash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/icon-sprite.svg b/assets/img/icon-sprite.svg index 53e6139c..c043e003 100644 --- a/assets/img/icon-sprite.svg +++ b/assets/img/icon-sprite.svg @@ -1 +1,116 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/js/theme/cart.js b/assets/js/theme/cart.js index a0fdd6f8..274075ef 100644 --- a/assets/js/theme/cart.js +++ b/assets/js/theme/cart.js @@ -10,6 +10,7 @@ import CartItemDetails from './common/cart-item-details' import q$, { q$$ } from './global/selector' import trigger from './common/utils/trigger' import toggle from './global/toggle' +import addReviewsToCartItems from './custom/add-reviews-to-cart-items' export default class Cart extends PageManager { onReady() { @@ -30,6 +31,10 @@ export default class Cart extends PageManager { this.setApplePaySupport() this.bindEvents() + + const { storefrontApiToken } = this.context + + addReviewsToCartItems(storefrontApiToken) } setApplePaySupport() { @@ -261,15 +266,16 @@ export default class Cart extends PageManager { let preVal // cart update - q$('.js-cart-update', this.$cartContent)?.addEventListener('click', (event) => { - const $target = event.currentTarget + q$$('.js-cart-update', this.$cartContent)?.forEach(($btn) => { + $btn.addEventListener('click', (event) => { + const $target = event.currentTarget - event.preventDefault() + event.preventDefault() - // update cart quantity - cartUpdate($target) + // update cart quantity + cartUpdate($target) + }) }) - // cart qty manually updates q$$('.js-cart-item-qty-input', this.$cartContent).forEach(($input) => { $input.addEventListener('focus', function onQtyFocus() { diff --git a/assets/js/theme/cart/shipping-estimator.js b/assets/js/theme/cart/shipping-estimator.js index 5fd0138b..1699c666 100644 --- a/assets/js/theme/cart/shipping-estimator.js +++ b/assets/js/theme/cart/shipping-estimator.js @@ -27,7 +27,7 @@ export default class ShippingEstimator { tap: announceInputErrorMessage, }) - q$('.js-shipping-estimate-submit', this.$element)?.addEventListener('click', (event) => { + q$('.js-shipping-estimate-submit', this.$element).addEventListener('click', (event) => { // estimator error messages are being injected in html as a result // of user submit; clearing and adding role on submit provides // regular announcement of these error messages @@ -140,7 +140,10 @@ export default class ShippingEstimator { // When you change a country, you swap the state/province between an input and a select dropdown // Not all countries require the province to be filled // We have to remove this class when we swap since nod validation doesn't cleanup for us - q$(this.shippingEstimator).querySelector('.js-form-field-success').classList.remove('js-form-field-success') + const shippingEstimator = q$(this.shippingEstimator) + if (shippingEstimator) { + shippingEstimator.querySelector('.js-form-field-success')?.classList.remove('js-form-field-success') + } }) } @@ -177,7 +180,7 @@ export default class ShippingEstimator { event.preventDefault() utils.api.cart.getShippingQuotes(params, 'cart/shipping-quotes', (err, response) => { - q$('.js-shipping-quotes').innerHTML = response.content + q$('.js-shipping-quotes').innerHTML = response?.content // bind the select button q$('.js-select-shipping-quote').addEventListener('click', (clickEvent) => { diff --git a/assets/js/theme/common/state-country.js b/assets/js/theme/common/state-country.js index c61b4e0f..0eae5eec 100644 --- a/assets/js/theme/common/state-country.js +++ b/assets/js/theme/common/state-country.js @@ -8,26 +8,27 @@ import q$, { q$$ } from '../global/selector' * If there are no options from bcapp, a text field will be sent. This will create a select element to hold options after the remote request. * @returns {HTMLElement} */ -function makeStateRequired(stateElement, context) { +function makeStateRequired(stateElement) { /* eslint-disable no-param-reassign */ - stateElement.innerHTML = ` - - ` + const selectElement = document.createElement('select') + + selectElement.className = 'c-form__input c-form__input--select u-width-full' + + selectElement.id = stateElement.id + selectElement.name = stateElement.getAttribute('name') + selectElement.setAttribute('data-label', stateElement.dataset.label) + selectElement.setAttribute('data-field-type', stateElement.dataset.fieldType) + + stateElement.replaceWith(selectElement) const $hiddenInput = q$$('[name*="FormFieldIsText"]') $hiddenInput.forEach(($hi) => $hi.remove()) const $newElement = q$('[data-field-type="State"]') const $prevElement = $newElement.previousElementSibling - if ($prevElement.querySelector('small') === null) { + if ($prevElement?.querySelector('small') === null) { // String is injected from localizer - $prevElement.insertAdjacentHTML('beforeend', `${context.required}`) + $prevElement.insertAdjacentHTML('beforeend', `*`) } else { $prevElement.querySelector('small').style.display = 'block' } @@ -43,22 +44,25 @@ function makeStateRequired(stateElement, context) { */ function makeStateOptional(stateElement) { /* eslint-disable no-param-reassign */ - stateElement.innerHTML = ` - - ` + const inputElement = document.createElement('input') + inputElement.type = 'text' + + inputElement.className = 'js-form-input c-form__input u-width-full' + + inputElement.id = stateElement.id + inputElement.name = stateElement.getAttribute('name') + inputElement.setAttribute('data-label', stateElement.dataset.label) + inputElement.setAttribute('data-field-type', stateElement.dataset.fieldType) + + stateElement.replaceWith(inputElement) const $newElement = q$('[data-field-type="State"]') if ($newElement !== null) { insertStateHiddenField($newElement) - $newElement.previousElementSibling.querySelector('small').style.display = 'none' + if ($newElement.previousElementSibling?.querySelector('small')) { + $newElement.previousElementSibling.querySelector('small').style.display = 'none' + } } return $newElement @@ -75,7 +79,7 @@ function addOptions(statesArray, $selectElement, options) { container.push(``) - if (!isEmpty($selectElement)) { + if (isEmpty($selectElement)) { statesArray.states.forEach((stateObj) => { if (options.useIdForStates) { container.push(``) diff --git a/assets/js/theme/common/utils/form-utils.js b/assets/js/theme/common/utils/form-utils.js index e1986e57..e97efffa 100644 --- a/assets/js/theme/common/utils/form-utils.js +++ b/assets/js/theme/common/utils/form-utils.js @@ -321,13 +321,14 @@ const Validators = { * @param field */ cleanUpStateValidation: (field) => { - const $fieldClassElement = q$(`[data-type="${field.dataset.fieldType}"]`) - - Object.keys(nod.classes).forEach((value) => { - if ($fieldClassElement.classList.contains(nod.classes[value])) { - $fieldClassElement.classList.remove(nod.classes[value]) - } - }) + if (field.dataset.fieldType) { + const $fieldClassElement = q$(`[data-field-type="${field.dataset.fieldType}"]`) + Object.keys(nod.classes).forEach((value) => { + if ($fieldClassElement.classList.contains(nod.classes[value])) { + $fieldClassElement.classList.remove(nod.classes[value]) + } + }) + } }, } diff --git a/assets/js/theme/custom/add-reviews-to-cart-items.js b/assets/js/theme/custom/add-reviews-to-cart-items.js new file mode 100644 index 00000000..b8d93be4 --- /dev/null +++ b/assets/js/theme/custom/add-reviews-to-cart-items.js @@ -0,0 +1,56 @@ +/** + * Add reviews to cart items via GraphQL + */ +export default function addReviewsToCartItems(storefrontApiToken) { + const cartItems = document.querySelectorAll('.js-item-row') + if (cartItems.length > 0) { + cartItems.forEach((product) => { + const productId = product.getAttribute('data-type-product-id') + fetch('/graphql', { + method: 'POST', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${storefrontApiToken}`, + }, + body: JSON.stringify({ + query: ` + query getProductRating { + site { + product(entityId: ${productId}) { + reviewSummary { + numberOfReviews + summationOfRatings + } + } + } + } + `, + }), + }) + .then((res) => res.json()) + .then((data) => { + const summationOfRatings = data?.data?.site?.product?.reviewSummary?.summationOfRatings + const numberOfReviews = data?.data?.site?.product?.reviewSummary?.numberOfReviews + const ratingElement = document.querySelector(`[data-type-product-id="${productId}"] .c-cart__item-rating`) + const ratingLink = document.querySelector(`[data-type-product-id="${productId}"] .c-cart__item-rating-link`) + + ratingLink.innerHTML = `${numberOfReviews} reviews` + + if (ratingElement) { + ratingElement.setAttribute('data-product-rating', summationOfRatings) + const filledStars = ratingElement.querySelectorAll('.c-cart-item__filled-stars svg') + const unfilledStars = ratingElement.querySelectorAll('.c-cart-item__unfilled-stars svg') + + for (let i = 0; i < summationOfRatings; i++) { + filledStars[i].classList.remove('u-hidden') + } + + for (let i = 0; i < 5 - summationOfRatings; i++) { + unfilledStars[i].classList.remove('u-hidden') + } + } + }) + }) + } +} diff --git a/assets/scss/components/_cart.scss b/assets/scss/components/_cart.scss new file mode 100644 index 00000000..fcbd6ca5 --- /dev/null +++ b/assets/scss/components/_cart.scss @@ -0,0 +1,178 @@ +.c-cart__totals { + display: flex; + flex-direction: column; + align-items: flex-end; +} + +.c-cart__content { + margin-bottom: rem-calc(24px); +} + +.c-cart__item-wrapper { + display: flex; + flex-direction: column; + gap: 3rem; +} + +.c-cart__item { + display: flex; + flex-direction: column; + gap: rem-calc(24px); + + @include bp(small) { + flex-direction: row; + gap: rem-calc(48px); + } +} + +.c-cart__item-image-wrapper { + position: relative; + display: block; + aspect-ratio: 17.75 / 26.5; + width: 50%; + height: auto; + max-width: 17.75rem; + object-fit: cover; + + @include bp(small) { + width: 100%; + } +} + +.c-cart__item-image { + position: absolute; + width: 100%; + height: 100%; + object-fit: cover; +} + +.c-cart__item-information { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.c-cart__item-title { + color: $color-black; + font-family: $font-semi-bold; + font-size: 2rem; + font-style: normal; + font-weight: 600; + line-height: 2.5rem; + text-decoration: none; +} + +.c-cart__item-options { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.c-cart__option-name { + color: $color-black; + font-family: $font-semi-bold; + font-size: 1rem; + font-style: normal; + font-weight: 600; + line-height: 1.5rem; + margin: 0; +} + +.c-cart__option-value { + color: $color-neutrals-500; + font-family: $font-regular; + font-size: 1rem; + font-style: normal; + font-weight: 400; + line-height: 1.5rem; + margin: 0; +} + +.c-cart__item-actions { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1.5rem; + width: fit-content; +} + +.c-cart__item-inputs { + padding: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.5rem; + background-color: $color-white; + border-radius: 0.25rem; + border: 1px solid $color-neutrals-75; +} + +.c-cart__button-remove { + display: flex; + justify-content: center; + align-items: center; + background: none; + border: 0; + outline: none; + padding: 0; + margin: 0; + cursor: pointer; +} + +.c-cart__item-qty-input { + color: $color-neutrals-500; + text-align: center; + font-family: $font-regular; + font-size: 1rem; + font-style: normal; + font-weight: 400; + line-height: 1.5rem; + width: 1.75rem; + border: 0; +} + +.c-cart__item-qty-btn { + border: 0; + background: none; + outline: none; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; +} + +.c-cart__checkout-button-wrapper { + display: flex; + flex-direction: column; + align-items: flex-end; +} + +.c-cart__item-rating-wrapper { + display: flex; + align-items: center; + gap: rem-calc(8px); +} + +.c-cart__item-rating-link { + color: $color-primary-300; + font-family: $font-semi-bold; + font-size: rem-calc(14px); + line-height: rem-calc(16px); + font-weight: 600; + letter-spacing: 0; + text-align: center; + + &:hover { + color: $color-primary-300; + } +} + +.c-cart__item-head { + display: flex; + flex-direction: column; + gap: rem-calc(12px); +} + +.c-cart__icon { + max-width: rem-calc(24px); +} diff --git a/assets/scss/components/_components.scss b/assets/scss/components/_components.scss index f34a1234..2f918c12 100644 --- a/assets/scss/components/_components.scss +++ b/assets/scss/components/_components.scss @@ -43,3 +43,9 @@ @import 'cta-panel'; @import 'product-compare'; @import 'blog'; +@import 'cart'; +@import 'totals'; +@import 'shipping-estimator'; +@import 'coupon-form'; +@import 'order-total'; +@import 'star'; diff --git a/assets/scss/components/_coupon-form.scss b/assets/scss/components/_coupon-form.scss new file mode 100644 index 00000000..c69e7775 --- /dev/null +++ b/assets/scss/components/_coupon-form.scss @@ -0,0 +1,5 @@ +.c-coupon-form { + display: flex; + flex-direction: column; + gap: rem-calc(12px); +} diff --git a/assets/scss/components/_order-total.scss b/assets/scss/components/_order-total.scss new file mode 100644 index 00000000..afe570b0 --- /dev/null +++ b/assets/scss/components/_order-total.scss @@ -0,0 +1,6 @@ +.c-order-total { + display: flex; + justify-content: center; + align-items: center; + gap: 1.5rem; +} \ No newline at end of file diff --git a/assets/scss/components/_shipping-estimator.scss b/assets/scss/components/_shipping-estimator.scss new file mode 100644 index 00000000..d73dbae5 --- /dev/null +++ b/assets/scss/components/_shipping-estimator.scss @@ -0,0 +1,7 @@ +.c-shipping-estimator { + display: flex; + flex-direction: column; + align-items: flex-end; + text-align: right; + gap: rem-calc(12px); +} diff --git a/assets/scss/components/_star.scss b/assets/scss/components/_star.scss new file mode 100644 index 00000000..3c924c27 --- /dev/null +++ b/assets/scss/components/_star.scss @@ -0,0 +1,5 @@ +.c-star { + max-width: rem-calc(12px); + max-height: rem-calc(12px); + fill: transparent; +} diff --git a/assets/scss/components/_totals.scss b/assets/scss/components/_totals.scss new file mode 100644 index 00000000..6bb573ce --- /dev/null +++ b/assets/scss/components/_totals.scss @@ -0,0 +1,47 @@ +.c-totals__subtotal { + display: flex; + justify-content: flex-end; + align-items: center; + gap: rem-calc(24px); +} + +.c-totals__shipping-total { + display: flex; + justify-content: flex-end; + align-items: center; + gap: rem-calc(24px); + margin-bottom: rem-calc(12px); +} + +.c-totals__label { + color: $color-neutrals-300; + font-family: $font-semi-bold; + font-size: rem-calc(20px); + line-height: rem-calc(24px); + font-weight: 600; + letter-spacing: 0; + text-align: center; +} + +.c-totals__value { + @extend .c-totals__label; + color: $color-black; +} + +.c-totals__shipping-estimator { + margin-bottom: rem-calc(24px); +} + +.c-totals__cart-total { + font-size: rem-calc(32px); + line-height: rem-calc(40px); + text-align: right; + margin-block: rem-calc(24px); +} + +.c-totals__checkout-button { + display: flex; + justify-content: center; + align-items: center; + gap: rem-calc(8px); +} diff --git a/lang/en.json b/lang/en.json index fa9a8ab1..5ff7e34c 100755 --- a/lang/en.json +++ b/lang/en.json @@ -48,7 +48,7 @@ "multiple": "check out with multiple addresses", "or": "or" }, - "button": "Check out", + "button": "Go to checkout", "empty_cart": "Your cart is empty", "title": "Click here to proceed to checkout", "item": "Item", @@ -68,6 +68,7 @@ "checkout_multiple": "or check out with multiple addresses", "view_cart": "View Cart" }, + "title": "Cart", "label": "Your Cart ({quantity, plural, one {# item} other {# items}})", "is_empty": "Your cart is empty", "invalid_entry_message": "[ENTRY] is not a valid entry", diff --git a/templates/components/cart/content.html b/templates/components/cart/content.html index 24b23492..5d1a232d 100644 --- a/templates/components/cart/content.html +++ b/templates/components/cart/content.html @@ -1,192 +1,141 @@
-
-
{{lang 'cart.checkout.item'}}
-
{{lang 'cart.checkout.price'}}
-
{{lang 'cart.checkout.quantity'}}
-
{{lang 'cart.checkout.total'}}
-
-
+
{{#each cart.items}} -
-
+
+
{{#if type '==' 'GiftCertificate'}} {{lang 'cart.gift_certificates.gift_certificate'}} {{else}} {{> components/common/image image=image fallback_size=../theme_settings.product_thumb_size default_image=../theme_settings.default_image_product + class="c-cart__item-image" }} {{/if}}
-
- {{#if brand.name}} -

{{brand.name}}

- {{/if}} -
- +
+
+ {{name}} +
+ + +
- {{#if release_date}} -

({{release_date}})

- {{/if}} {{#if options}} -
+
{{#each options}} -
{{name}}:
-
- {{#if is_file}} - - {{value}} - - {{else}} - {{> components/common/product-options}} - {{/if}} -
+

+ {{name}} + * +

+

{{> components/common/product-options}}

{{/each}} -
- - - {{lang 'common.change'}} - - {{/if}} - - {{#if type '==' 'GiftCertificate'}} - - {{lang 'common.change'}} - - {{/if}} - {{> components/cart/item-giftwrap this}} - - {{#if event_date}} -
-
- {{event_date.name}} -
-
- {{event_date.date}} -
-
+ + {{lang 'common.change'}} + +
{{/if}} -
-
- {{lang 'cart.checkout.price'}} - - {{#or ../customer (unless ../settings.hide_price_from_guests) (if type '==' 'GiftCertificate')}} - - {{price.formatted}} - - - {{#if price_discounted}} - - {{price_discounted.formatted}} - - {{/if}} - {{else}} - {{> components/common/login-for-pricing}} - {{/or}} -
- -
- - -
- {{#if can_modify}} - - {{/if}} - - {{#if can_modify}} - + {{/if}} + - - {{lang 'products.quantity_increase' name=name}} - - - - - - {{/if}} + data-action="manualQtyChange" + aria-label="{{name}}" + aria-live="polite"{{#unless can_modify}} disabled{{/unless}}> + {{#if can_modify}} + + {{/if}} +
+
+ {{#or ../customer (unless ../settings.hide_price_from_guests) (if type '==' 'GiftCertificate')}} + + {{total.formatted}} + + + {{#if total_discounted}} + + {{total_discounted.formatted}} + + {{/if}} + {{else}} + -- + {{/or}} + {{#or can_modify (if type '==' 'GiftCertificate')}} + + {{/or}} +
- -
- - {{lang 'cart.checkout.total'}} - - - {{#or ../customer (unless ../settings.hide_price_from_guests) (if type '==' 'GiftCertificate')}} - - {{total.formatted}} - - - {{#if total_discounted}} - - {{total_discounted.formatted}} - - {{/if}} - {{else}} - -- - {{/or}} - {{#or can_modify (if type '==' 'GiftCertificate')}} - - {{/or}} -
{{/each}}
diff --git a/templates/components/cart/coupon-input.html b/templates/components/cart/coupon-input.html index 69b7010b..4063b006 100644 --- a/templates/components/cart/coupon-input.html +++ b/templates/components/cart/coupon-input.html @@ -1,20 +1,7 @@ -
- - - -
- - +
-
- -
-
- -
+
+ + +
-
- -
-
- -
- - - +
+ + +
+ +
-
  • -
    - {{lang 'cart.checkout.subtotal'}}: -
    -
    - {{#or customer (unless settings.hide_price_from_guests)}} - - {{cart.sub_total.formatted}} - - {{else}} - {{> components/common/login-for-pricing}} - {{/or}} -
    -
  • +
    +
    + {{lang 'cart.checkout.subtotal'}}: + {{#or customer (unless settings.hide_price_from_guests)}} + + {{cart.sub_total.formatted}} + + {{else}} + {{> components/common/login-for-pricing}} + {{/or}} +
    {{#if cart.gift_wrapping_cost.value}} -
  • -
    - {{lang 'cart.checkout.gift_wrapping'}}: -
    -
    - - {{cart.gift_wrapping_cost.formatted}} - -
    -
  • +
    + {{lang 'cart.checkout.gift_wrapping'}}: + + {{cart.gift_wrapping_cost.formatted}} + +
    {{/if}} {{#if cart.shipping_handling.show_estimator}} -
  • -
    - {{lang 'cart.checkout.shipping'}}: -
    +
    {{> components/cart/shipping-estimator cart.shipping_handling}} -
  • +
    {{/if}} {{#each cart.taxes}} {{#unless included}} -
  • -
    - {{name}}: -
    -
    - {{cost.formatted}} -
    -
  • +
    + {{name}}: + {{cost.formatted}} +
    {{/unless}} {{/each}} {{#if cart.discount }} -
  • -
    - {{lang 'cart.discount'}}: -
    -
    +
    + {{lang 'cart.discount'}}: + {{cart.discount.formatted}} -
    -
  • + +
    {{/if}} {{#if cart.coupons}} {{#each cart.coupons}} -
  • +
    - + {{lang 'cart.coupons.code_label' code=code}}
    @@ -70,68 +53,53 @@
    -
    - {{discount.formatted}} -
    -
  • + {{discount.formatted}} +
    {{/each}} {{else}} -
  • -
    - {{lang 'cart.coupon_code'}}: -
    +
    {{> components/cart/coupon-input}} -
  • +
    {{/if}} {{#if settings.gift_certificates_enabled}} {{#each cart.gift_certificates}} -
  • +
    - + {{lang 'cart.gift_certificates.code_label' code=code}} - + {{remaining.formatted}} | {{lang 'cart.gift_certificates.remove'}}
    -
    +
    {{used.formatted}}
    -
  • - {{/each}} -
  • -
    - {{lang 'cart.gift_certificates.gift_certificate'}}:
    + {{/each}} +
    + {{lang 'cart.gift_certificates.gift_certificate'}}: {{> components/cart/gift-certificate-input}} -
  • +
    {{/if}} -
  • -
    - {{lang 'cart.checkout.grand_total'}}: -
    -
    - {{#or customer (unless settings.hide_price_from_guests)}} - - {{cart.grand_total.formatted}} - - {{else}} - {{> components/common/login-for-pricing}} - {{/or}} -
    -
  • +
    + {{lang 'cart.checkout.grand_total'}}: + {{#or customer (unless settings.hide_price_from_guests)}} + + {{cart.grand_total.formatted}} + + {{else}} + {{> components/common/login-for-pricing}} + {{/or}} +
    {{#each cart.taxes}} {{#if included}} -
  • -
    - {{concat name (lang 'cart.included_in_total')}}: -
    -
    - {{cost.formatted}} -
    -
  • +
    + {{concat name (lang 'cart.included_in_total')}}: + {{cost.formatted}} +
    {{/if}} {{/each}} - +
    diff --git a/templates/components/common/star.html b/templates/components/common/star.html new file mode 100644 index 00000000..0c7df5f6 --- /dev/null +++ b/templates/components/common/star.html @@ -0,0 +1,9 @@ +{{#if status '===' 'filled'}} + + + +{{else}} + + + +{{/if}} \ No newline at end of file diff --git a/templates/pages/cart.html b/templates/pages/cart.html index 8767be70..dc7a6e1d 100644 --- a/templates/pages/cart.html +++ b/templates/pages/cart.html @@ -4,77 +4,80 @@ {{inject 'cancelButtonText' (lang 'common.cancel')}} {{#partial "page"}} {{inject 'invalidEntryMessage' (lang 'cart.invalid_entry_message')}} +{{inject 'storefrontApiToken' settings.storefront_api.token}} -
    -
    - {{> components/common/breadcrumbs breadcrumbs=breadcrumbs}} +{{> components/common/breadcrumbs breadcrumbs=breadcrumbs}} - {{> components/cart/page-title}} +

    {{lang 'cart.title'}}

    -
    - {{> components/cart/status-messages}} -
    +
    - {{#if cart.items.length}} -
    +
    + {{> components/cart/status-messages}} +
    -
    - {{> components/cart/content}} -
    + {{#if cart.items.length}} +
    -
    - {{> components/cart/totals}} -
    +
    + {{> components/cart/content}} +
    - {{{region name="cart_below_totals"}}} +
    + {{> components/cart/totals}} +
    - {{#or customer (unless settings.hide_price_from_guests)}} - {{#if cart.additional_checkout_buttons}} -
    - {{/if}} + {{{region name="cart_below_totals"}}} - {{#if cart.show_primary_checkout_button}} -
    - - {{lang 'cart.checkout.button'}} - - {{#if cart.show_multiple_address_shipping}} - - {{lang 'cart.preview.checkout_multiple'}} - - {{/if}} -
    - {{else}} - - {{/if}} + {{#or customer (unless settings.hide_price_from_guests)}} + {{#if cart.additional_checkout_buttons}} +
    + {{/if}} - {{#if cart.additional_checkout_buttons}} -
    - {{> components/cart/additional-checkout-buttons}} -
    - {{/if}} + {{#if cart.show_primary_checkout_button}} +
    + + + + + {{lang 'cart.checkout.button'}} + + {{#if cart.show_multiple_address_shipping}} + + {{lang 'cart.preview.checkout_multiple'}} + + {{/if}} +
    {{else}} -
    - - {{lang 'cart.login_to_checkout'}} + - {{/or}} + {{/if}} + {{#if cart.additional_checkout_buttons}} +
    + {{> components/cart/additional-checkout-buttons}} +
    + {{/if}} {{else}} -
    - {{lang 'cart.checkout.empty_cart'}} + - {{/if}} -
    + {{/or}} + + {{else}} +
    + {{lang 'cart.checkout.empty_cart'}} +
    + {{/if}}
    {{/partial}} {{> layout/base}}