Commit cc0489ae authored by Artem's avatar Artem

improve shopping cart using ajax

parent 833c0e38
...@@ -14,24 +14,21 @@ class Cart /*extends Model*/ ...@@ -14,24 +14,21 @@ class Cart /*extends Model*/
$this->total_price = 0; $this->total_price = 0;
} }
public function updateTotalQty() public function updateTotalPosAmount()
{ {
$result = 0; $this->total_qty = count($this->items);
foreach ($this->items as $item)
{
$result += $item['qty'];
}
$this->total_qty = $result;
} }
public function updateTotalPrice() public function updatePrices()
{ {
$result = 0; $total_price = 0;
foreach ($this->items as $item) foreach ($this->items as $id => $item)
{ {
$result += $item['qty'] * $item['item']->price; $subtotal_price = $item['qty'] * $item['item']->price;
$this->items[$id]['subtotal_price'] = $subtotal_price;
$total_price += $subtotal_price;
} }
$this->total_price = $result; $this->total_price = $total_price;
} }
public function addItem($id) public function addItem($id)
...@@ -42,27 +39,34 @@ class Cart /*extends Model*/ ...@@ -42,27 +39,34 @@ class Cart /*extends Model*/
$this->items[$id] = [ $this->items[$id] = [
'qty' => 1 'qty' => 1
]; ];
} }
$this->total_qty++; $this->updateTotalPosAmount();
} }
public function updateQty($products_qty) public function updateQty($product_id, $changed_qty)
{ {
foreach ($products_qty as $id => $qty) { if (array_key_exists($product_id, $this->items)) {
if ($qty <= 0) { if ($changed_qty <= 0) {
$this->removeItem($id); $this->removeItem($product_id);
} else { } else {
$this->items[$id]['qty'] = (int)$qty; $this->items[$product_id]['qty'] = $changed_qty;
$this->updateTotalQty();
} }
} else {
$this->addItem($product_id);
$this->items[$product_id]['qty'] = $changed_qty;
} }
$this->updateCurrentItems();
$this->updatePrices();
} }
public function removeItem($id) public function removeItem($id)
{ {
unset($this->items[$id]); unset($this->items[$id]);
$this->updateTotalQty(); $this->updateTotalPosAmount();
} }
public function updateCurrentItems() public function updateCurrentItems()
...@@ -81,6 +85,6 @@ class Cart /*extends Model*/ ...@@ -81,6 +85,6 @@ class Cart /*extends Model*/
$this->items[$product->id]['item'] = $product; $this->items[$product->id]['item'] = $product;
} }
$this->updateTotalPrice(); $this->updatePrices();
} }
} }
...@@ -17,11 +17,11 @@ class CartController extends Controller ...@@ -17,11 +17,11 @@ class CartController extends Controller
} }
$cart = Session::get('cart'); $cart = Session::get('cart');
// need to take products from database because product data may change // need to take products from database because product data may change
$cart->updateCurrentItems(); $cart->updateCurrentItems();
$products = $cart->items;
return view('cart', compact('cart','products')); return view('cart', compact('cart'));
} }
public function addToCart(Product $product) public function addToCart(Product $product)
...@@ -36,14 +36,17 @@ class CartController extends Controller ...@@ -36,14 +36,17 @@ class CartController extends Controller
} }
return $cart->total_qty; return $cart->total_qty;
} }
public function updateQtyInCart(Request $request) public function updateQtyInCart(Request $request)
{ {
$products_qty = json_decode($request->productsQty, true); if (!Session::has('cart')) {
return route('homepage');
}
$cart = Session::get('cart'); $cart = Session::get('cart');
$cart->updateQty($products_qty);
$cart->updateQty($request->productId, $request->changedQty);
if (!$cart->total_qty) { if (!$cart->total_qty) {
Session::forget('cart'); Session::forget('cart');
...@@ -51,17 +54,18 @@ class CartController extends Controller ...@@ -51,17 +54,18 @@ class CartController extends Controller
} }
} }
public function removeFromCart(Product $product) public function removeFromCart(Request $request)
{ {
$cart = Session::get('cart'); $cart = Session::get('cart');
$cart->removeItem($product->id); $cart->removeItem($request->productId);
if (!$cart->total_qty) { if (!$cart->total_qty) {
Session::forget('cart'); Session::forget('cart');
return route('homepage'); return route('homepage');
} }
$cart->updateCurrentItems();
} }
public function clearCart() public function clearCart()
...@@ -69,4 +73,25 @@ class CartController extends Controller ...@@ -69,4 +73,25 @@ class CartController extends Controller
Session::forget('cart'); Session::forget('cart');
return redirect(route('homepage')); return redirect(route('homepage'));
} }
public function getItems()
{
$cart = Session::get('cart');
// make array of products in order to get correct order of items in js
$cart_products = [];
foreach ($cart->items as $item) {
$cart_products[] = $item;
}
$response = [
'cart' => $cart,
'products' => $cart_products,
'update_item_url' => route('cart.updateQtyInCart'),
'remove_item_url' => route('cart.removeFromCart'),
'item_url' => '/product/'
];
return json_encode($response);
}
} }
...@@ -37,7 +37,8 @@ class OrderController extends Controller ...@@ -37,7 +37,8 @@ class OrderController extends Controller
'ordered_reference' => $product->reference, 'ordered_reference' => $product->reference,
'ordered_price' => $product->price, 'ordered_price' => $product->price,
'ordered_qty' => $item['qty'], 'ordered_qty' => $item['qty'],
'subtotal_price' => $product->price * $item['qty'], 'subtotal_price' => $item['subtotal_price'],
// 'subtotal_price' => $product->price * $item['qty'],
]); ]);
} }
......
function setUpdateCartQtyEventListener() { class Cart {
document.querySelector('.js-update-qty-btn').addEventListener('click', function(e) { constructor(cartElem) {
this.cartHtmlElem = cartElem;
this.getItemsUrl = cartElem.dataset.getItemsUrl;
}
const actionUrl = this.dataset.action; generateProductRow(product) {
return `<tr>
<td>
<div class="row">
<div class="col-sm-3 hidden-xs"><img src="/img/${product.item.type}.jpg" width="100" height="100" alt="${product.item.reference}" class="img-responsive"/></div>
<div class="col-sm-9">
<h4 class="nomargin"><a href="${this.itemUrl + product.item.id}">${product.item.reference}</a></h4>
<p>${product.item.description_short}</p>
</div>
</div>
</td>
<td>€ ${product.item.price}</td>
<td>
<input type="number"
min="0"
class="js-qty-input form-control text-center"
data-product-id="${product.item.id}"
value="${product.qty}">
</td>
<td class="text-center">€ ${product.subtotal_price}</td>
<td class="actions text-right">
<button class="js-remove-btn btn btn-danger btn-sm"
data-action="${this.removeItemUrl}"
data-product-id="${product.item.id}"
>Remove</button>
</td>
</tr>`;
}
const qtyInputs = document.querySelectorAll('.js-qty-input'); showProducts() {
let productsList = '';
const productsQty = {}; for (const item in this.products) {
const product = this.products[item];
productsList += this.generateProductRow(product);
}
qtyInputs.forEach(item => { this.cartHtmlElem.innerHTML = productsList;
const productId = item.dataset.product_id; document.querySelector('.amount-in-cart').textContent = this.positionsAmount;
productsQty[productId] = item.value; document.querySelector('.js-total-cart-price').textContent = 'Total € ' + this.totalPrice;
}); }
removeItemFromCart(e) {
if (!e.target.classList.contains('js-remove-btn')) return;
const actionUrl = e.target.dataset.action;
const productId = e.target.dataset.productId;
axios.post(actionUrl, { axios.post(actionUrl, {
productsQty: JSON.stringify(productsQty) productId: productId,
}) })
.then(function (response) { .then( (response) => {
const redirectLinkWhenCartIsEmpty = response.data; const redirectLinkWhenCartIsEmpty = response.data;
if (redirectLinkWhenCartIsEmpty) { if (redirectLinkWhenCartIsEmpty) {
window.location.replace(redirectLinkWhenCartIsEmpty); window.location.replace(redirectLinkWhenCartIsEmpty);
} else { } else {
document.location.reload(true); document.querySelector('.js-cart').removeEventListener('click', this.removeItemFromCart);
cart.show();
toastr.success('Product deleted');
} }
}) })
.catch(function (error) { .catch(function (error) {
console.log(error); console.log(error);
toastr.error('Error, something went wrong');
}); });
}); }
}
function setRemoveItemEventListener() { setUpdateItemQtyEventListener() {
document.querySelector('.js-products-in-cart').addEventListener('click', function(e) { document.querySelectorAll('.js-qty-input').forEach(changeQtyInput => {
if (!e.target.classList.contains('js-remove-btn')) return; let isChanged;
const actionUrl = e.target.dataset.action; changeQtyInput.addEventListener('input', (event) => {
if (isChanged) {
return;
}
axios.post(actionUrl) // this.show();
.then(function (response) { isChanged = true;
const actionUrl = this.updateItemUrl;
const productId = event.target.dataset.productId;
setTimeout(() => {
axios.post(actionUrl, {
productId: productId,
changedQty: event.target.value,
})
.then( (response) => {
const redirectLinkWhenCartIsEmpty = response.data; const redirectLinkWhenCartIsEmpty = response.data;
if (redirectLinkWhenCartIsEmpty) { if (redirectLinkWhenCartIsEmpty) {
window.location.replace(redirectLinkWhenCartIsEmpty); window.location.replace(redirectLinkWhenCartIsEmpty);
} else { } else {
document.location.reload(true); cart.show();
toastr.success('Quantity updated');
} }
}) })
.catch(function (error) { .catch(function (error) {
console.log(error); console.log(error);
toastr.error('Error, something went wrong'); toastr.error('Error, something went wrong');
}); });
isChanged = false;
}, 1000);
});
}); });
}
events() {
document.querySelector('.js-cart').addEventListener('click', this.removeItemFromCart );
this.setUpdateItemQtyEventListener();
}
show() {
axios.get(this.getItemsUrl)
.then( response => {
// this.products = response.data.cart.items;
this.products = response.data.products;
this.positionsAmount = response.data.cart.total_qty;
this.totalPrice = response.data.cart.total_price;
this.updateItemUrl = response.data.update_item_url;
this.removeItemUrl = response.data.remove_item_url;
this.itemUrl = response.data.item_url;
this.showProducts();
this.events();
})
.catch(function (error) {
console.log(error);
alert('Something went wrong');
});
}
} }
setUpdateCartQtyEventListener(); const cartElem = document.querySelector('.js-cart');
setRemoveItemEventListener();
const cart = new Cart(cartElem);
cart.show();
...@@ -61,8 +61,8 @@ ...@@ -61,8 +61,8 @@
</tr> </tr>
</thead> </thead>
<tbody class="js-products-in-cart"> <tbody class="js-cart" data-get-items-url="{{ route('cart.getItems') }}">
@foreach($products as $product) {{-- @foreach($products as $product)
<tr> <tr>
<td> <td>
<div class="row"> <div class="row">
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
>Remove</button> >Remove</button>
</td> </td>
</tr> </tr>
@endforeach @endforeach--}}
</tbody> </tbody>
<tfoot> <tfoot>
...@@ -97,11 +97,11 @@ ...@@ -97,11 +97,11 @@
<a href="{{ route('homepage') }}" class="btn btn-primary"> Continue Shopping</a> <a href="{{ route('homepage') }}" class="btn btn-primary"> Continue Shopping</a>
</td> </td>
<td colspan="2" class="text-right"> <td colspan="2" class="text-right">
<button class="js-update-qty-btn btn btn-warning" {{-- <button class="js-update-qty-btn btn btn-warning"--}}
data-action="{{ route('cart.updateQtyInCart') }}" {{-- data-action="{{ route('cart.updateQtyInCart') }}"--}}
>Update quantity</button> {{-- >Update quantity</button>--}}
</td> </td>
<td class="hidden-xs text-center"><b>Total € {{ $cart->total_price }}</b></td> <td class="hidden-xs text-center"><b class="js-total-cart-price"></b></td>
<td> <td>
<button class="btn btn-success btn-block" data-toggle="modal" data-target="#placeOrderModal"> <button class="btn btn-success btn-block" data-toggle="modal" data-target="#placeOrderModal">
Send order Send order
......
...@@ -30,8 +30,11 @@ Route::prefix('cart')->group(function() { ...@@ -30,8 +30,11 @@ Route::prefix('cart')->group(function() {
Route::get('/', 'CartController@index')->name('cart.index'); Route::get('/', 'CartController@index')->name('cart.index');
Route::post('/add/{product}', 'CartController@addToCart')->name('cart.addToCart'); Route::post('/add/{product}', 'CartController@addToCart')->name('cart.addToCart');
Route::post('/update', 'CartController@updateQtyInCart')->name('cart.updateQtyInCart'); Route::post('/update', 'CartController@updateQtyInCart')->name('cart.updateQtyInCart');
Route::post('/remove/{product}', 'CartController@removeFromCart')->name('cart.removeFromCart'); // Route::post('/remove/{product}', 'CartController@removeFromCart')->name('cart.removeFromCart');
Route::post('/remove', 'CartController@removeFromCart')->name('cart.removeFromCart');
Route::post('/clear', 'CartController@clearCart')->name('cart.clearCart'); Route::post('/clear', 'CartController@clearCart')->name('cart.clearCart');
Route::get('/getItems', 'CartController@getItems')->name('cart.getItems');
}); });
Route::middleware('auth')->prefix('profile')->group(function() { Route::middleware('auth')->prefix('profile')->group(function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment