Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update qty #1338

Merged
merged 2 commits into from Sep 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Require Webpack config only when used (reduce time to be ready for receiving messages from stencil-cli). [#1334](https://github.com/bigcommerce/cornerstone/pull/1334)
- Fixed amp page error related to store logo [#1323](https://github.com/bigcommerce/cornerstone/pull/1323)
- Add link to order status in account menu when viewing order [#1343](https://github.com/bigcommerce/cornerstone/pull/1343)
- Update cart when quantity changed manually (without using the increase and decrease arrows). [#1338](https://github.com/bigcommerce/cornerstone/pull/1338)

## 2.3.2 (2018-08-17)
- Fix zoom behavior for small images in gallery (turn off zoom if image is too small). [#1325](https://github.com/bigcommerce/cornerstone/pull/1325)
Expand Down
125 changes: 125 additions & 0 deletions assets/js/test-unit/theme/cart.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import $ from 'jquery'
import utils from '@bigcommerce/stencil-utils';
import Cart from '../../theme/cart.js';
import * as SweetAlert from 'sweetalert2';

var dataSpy;
var swalSpy;
var UpdateSpy;
var c = new Cart();
beforeEach(function() {
UpdateSpy = spyOn(utils.api.cart, 'itemUpdate');

dataSpy = function(requestedAction = null) {
spyOn(jQuery.fn, 'data').and.callFake(function() {
var param = arguments[0];
switch (param) {
case 'action':
return requestedAction;
case 'cartItemid':
return '11111';
case 'quantityMax':
return 5;
case 'quantityMin':
return 1;
case 'quantityMinError':
return 'min error';
case 'quantityMaxError':
return ' max error';
default:
return null;
}
})
};
});

var $dom = $('<table class="cart" data-cart-quantity="2">\
<thead class="cart-header">\
<tr>\
<th class="cart-header-item" colspan="2">Item</th>\
<th class="cart-header-item">Price</th>\
<th class="cart-header-item cart-header-quantity">Quantity</th>\
<th class="cart-header-item">Total</th>\
</tr>\
</thead>\
<tbody class="cart-list">\
<tr class="cart-item" data-item-row="">\
<td class="cart-item-block cart-item-figure">\
<img class="cart-item-image lazyautosizes lazyloaded" data-sizes="auto" src="www.example.com" data-src="www.example.com" alt="[Sample] product" title="[Sample] product">\
</td>\
<td class="cart-item-block cart-item-title">\
<h4 class="cart-item-name"><a href="/fog-linen-chambray-towel-beige-stripe/">[Sample] Fog Linen Chambray Towel - Beige Stripe</a></h4>\
<dl class="definitionList">\
<dt class="definitionList-key">Size:</dt>\
<dd class="definitionList-value">\
XS\
</dd>\
<dt class="definitionList-key">Color:</dt>\
<dd class="definitionList-value">\
Silver\
</dd>\
</dl>\
<a href="#" data-item-edit="item-id">Change</a>\
</td>\
<td class="cart-item-block cart-item-info">\
<span class="cart-item-label">Price</span>\
<span class="cart-item-value ">$49.00</span>\
</td>\
<td class="cart-item-block cart-item-info cart-item-quantity">\
<label class="form-label cart-item-label" for="qty-item-id">Quantity:</label>\
<div class="form-increment">\
<button class="button button--icon" data-cart-update="" data-cart-itemid="item-id" data-action="dec">\
<span class="is-srOnly">Decrease Quantity:</span>\
<i class="icon" aria-hidden="true"><svg><use xmlns:xlink="www.ccc.com"></use></svg></i>\
</button>\
<input class="form-input form-input--incrementTotal cart-item-qty-input" id="item-id" name="qty-item-id" type="tel" value="2" data-quantity-min="0" data-quantity-max="" data-quantity-min-error="The minimum purchasable quantity is 0" data-quantity-max-error="The maximum purchasable quantity is null" min="1" pattern="[0-9]*" data-cart-itemid="item-id" data-action="manualQtyChange" aria-live="polite">\
<button class="button button--icon" data-cart-update="" data-cart-itemid="item-id" data-action="inc">\
<span class="is-srOnly">Increase Quantity:</span>\
<i class="icon" aria-hidden="true"><svg><use xmlns:xlink="www.ddd.com"></use></svg></i>\
</button>\
</div>\
</td>\
<td class="cart-item-block cart-item-info">\
<span class="cart-item-label">Total</span>\
<strong class="cart-item-value ">$98.00</strong>\
<a class="cart-remove icon" data-cart-itemid="item-id" href="#" data-confirm-delete="Are you sure you want to delete this item?">\
<svg><use xmlns:xlink="www.eee.com" xlink:href="#icon-close"></use></svg>\
</a>\
</td>\
</tr>\
</tbody>\
</table>')

c.onReady();

describe('cartUpdate', () => {
it('should INCRIMENT qty', () => {
dataSpy
dataSpy('inc');
spyOn(jQuery.fn, 'val').and.returnValue(2);
c.cartUpdate($dom);

expect(UpdateSpy).toHaveBeenCalledWith('11111', 3, jasmine.any(Function));
});

it('should DECREMENT qty', () => {
dataSpy
dataSpy('dec');
spyOn(jQuery.fn, 'val').and.returnValue(2);
c.cartUpdate($dom);

expect(UpdateSpy).toHaveBeenCalledWith('11111', 1, jasmine.any(Function));
});
});

describe('cartUpdateQtyTextChange', () => {
it('should CHANGE qty completly based on the cart-item-qty-input', () => {
dataSpy
dataSpy('manualQtyChange');
spyOn(jQuery.fn, 'attr').and.returnValue(5);
spyOn(jQuery.fn, 'val').and.returnValue(2);
c.cartUpdateQtyTextChange($dom);

expect(UpdateSpy).toHaveBeenCalledWith('11111', 5, jasmine.any(Function));
});
});
65 changes: 64 additions & 1 deletion assets/js/theme/cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export default class Cart extends PageManager {
const minError = $el.data('quantityMinError');
const maxError = $el.data('quantityMaxError');
const newQty = $target.data('action') === 'inc' ? oldQty + 1 : oldQty - 1;

// Does not quality for min/max quantity
if (newQty < minQty) {
return swal({
Expand Down Expand Up @@ -61,6 +60,57 @@ export default class Cart extends PageManager {
});
}

cartUpdateQtyTextChange($target, preVal = null) {
const itemId = $target.data('cartItemid');
const $el = $(`#qty-${itemId}`);
const maxQty = parseInt($el.data('quantityMax'), 10);
const minQty = parseInt($el.data('quantityMin'), 10);
const oldQty = preVal !== null ? preVal : minQty;
const minError = $el.data('quantityMinError');
const maxError = $el.data('quantityMaxError');
const newQty = parseInt(Number($el.attr('value')), 10);
let invalidEntry;
// Does not quality for min/max quantity
if (!newQty) {
invalidEntry = $el.attr('value');
$el.val(oldQty);
return swal({
text: `${invalidEntry} is not a valid entry`,
type: 'error',
});
} else if (newQty < minQty) {
$el.val(oldQty);
return swal({
text: minError,
type: 'error',
});
} else if (maxQty > 0 && newQty > maxQty) {
$el.val(oldQty);
return swal({
text: maxError,
type: 'error',
});
}

this.$overlay.show();
utils.api.cart.itemUpdate(itemId, newQty, (err, response) => {
this.$overlay.hide();

if (response.data.status === 'succeed') {
// if the quantity is changed "1" from "0", we have to remove the row.
const remove = (newQty === 0);

this.refreshContent(remove);
} else {
$el.val(oldQty);
swal({
text: response.data.errors.join('\n'),
type: 'error',
});
}
});
}

cartRemoveItem(itemId) {
this.$overlay.show();
utils.api.cart.itemRemove(itemId, (err, response) => {
Expand Down Expand Up @@ -162,7 +212,9 @@ export default class Cart extends PageManager {
bindCartEvents() {
const debounceTimeout = 400;
const cartUpdate = _.bind(_.debounce(this.cartUpdate, debounceTimeout), this);
const cartUpdateQtyTextChange = _.bind(_.debounce(this.cartUpdateQtyTextChange, debounceTimeout), this);
const cartRemoveItem = _.bind(_.debounce(this.cartRemoveItem, debounceTimeout), this);
let preVal;

// cart update
$('[data-cart-update]', this.$cartContent).on('click', event => {
Expand All @@ -174,6 +226,17 @@ export default class Cart extends PageManager {
cartUpdate($target);
});

// cart qty manually updates
$('.cart-item-qty-input', this.$cartContent).on('focus', function () {
preVal = this.value;
}).change(event => {
const $target = $(event.currentTarget);
event.preventDefault();

// update cart quantity
cartUpdateQtyTextChange($target, preVal);
});

$('.cart-remove', this.$cartContent).on('click', event => {
const itemId = $(event.currentTarget).data('cartItemid');
const string = $(event.currentTarget).data('confirmDelete');
Expand Down
4 changes: 3 additions & 1 deletion templates/components/cart/content.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ <h4 class="cart-item-name"><a href="{{url}}">{{name}}</a></h4>
<i class="icon" aria-hidden="true"><svg><use xlink:href="#icon-keyboard-arrow-down" /></svg></i>
</button>
{{/if}}
<input class="form-input form-input--incrementTotal"
<input class="form-input form-input--incrementTotal cart-item-qty-input"
id="qty-{{id}}"
name="qty-{{id}}"
type="tel"
Expand All @@ -110,6 +110,8 @@ <h4 class="cart-item-name"><a href="{{url}}">{{name}}</a></h4>
data-quantity-max-error="{{lang 'products.quantity_max' quantity=max_purchase_quantity}}"
min="1"
pattern="[0-9]*"
data-cart-itemid="{{id}}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we have this twice ?

data-action="manualQtyChange"
aria-live="polite"{{#unless can_modify}} disabled{{/unless}}>
{{# if can_modify}}
<button class="button button--icon" data-cart-update data-cart-itemid="{{id}}" data-action="inc">
Expand Down