Basket

  • In previous section we used a preliminary basket view (with only 3 fixed records) to test our Cart class
  • Now we we'll make this a 'real' basket where we can:
    • Add/remove items from the basket
    • Empty our basket
    • Place an order and add all items (in the basket) to the database

Add a record to the cart

  • The record detail page is the only place where we can add a record to our basket
  • Open resources/views/shop/show.blade.php
    • Update the path (href) behind the Add to cart link

 





<p>
    <a href="/basket/add/{{ $record->id }}" class="btn {{ $record->btnClass }} btn-sm btn-block mt-3
        {{ $record->stock == 0 ? 'disabled' : '' }}">
            <i class="fas fa-cart-plus mr-3"></i>Add to cart
    </a>
</p>
1
2
3
4
5
6
  • For a better UX, we can change the cursor if the link button is disabled

REMARKS

  • Open developer tools in Chrome and select an 'Add to cart' link button with the class disabled (choose a record that is out of stock)
  • Bootstrap adds the CSS rule pointer-events: none; to such a link button with the class disabled
    • This rule prevents the normal event (the link) to work and that's exactly what we want
    • The disadvantage of this rule however is that you can't change the cursor!
  • The solution is to change the cursor on the parent element with a bit of JavaScript
  • Open resources/js/VinylShop.js and change the cursor on the parent element of any element with classes btn and disabled


 


$(function(){
    ...
    $('.btn.disabled').parent().css('cursor', 'not-allowed');
});
1
2
3
4

Stop cursor if stock is 0

Send feedback to the user

  • Open app/Http/Controllers/BasketController.php and flash a message to the view (that already contains the sub-view shared/alert.blade.php to show such flash messages)





 



public function addToCart($id)
{
    $record = Record::findOrFail($id);
    $record->cover = $record->cover ?? "https://coverartarchive.org/release/$record->title_mbid/front-250.jpg";
    Cart::add($record);
    session()->flash('success', "The record <b>$record->title</b> from <b>$record->artist</b> has been added to your basket");
    return back();
}
1
2
3
4
5
6
7
8

Send feedback to the user

Update the view

  • Open resources/views/basket.blade.php
  • The login inside the basket view is as follows:
    • If the cart is empty: show a message (that the cart is empty)
    • If the cart is not empty:
      • Show all the items in a responsive table
      • Provide a link for each item to increase/decrease the number of items
      • Show the total price of all items in your basket
      • If the user is logged in, show a button to actually place the order
      • If the user is not logged in, show a message that he must login/register first

Show message if cart is empty

  • Remove all debug content inside the main section and add the following code:


 
 
 
 
 
 
 


@section('main')
    <h1>Basket</h1>
    @if( Cart::getTotalQty() == 0)
        <div class="alert alert-primary">
            Your basket is empty.
        </div>
    @else
        <!-- Cart comes here -->
    @endif
@endsection
1
2
3
4
5
6
7
8
9
10

Basket is empty

Show cart info

  • Update the code if the cart is not empty

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


@else
    <div class="table-responsive">
        <table class="table">
            <thead>
            <tr>
                <th>Qty</th>
                <th>Price</th>
                <th></th>
                <th>Record</th>
                <th></th>
            </tr>
            </thead>
            <tbody>
            @foreach(Cart::getRecords() as $record)
                <tr>
                    <td>{{ $record['qty'] }}</td>
                    <td>&nbsp;{{ $record['price'] }}</td>
                    <td>
                        <img class="img-thumbnail cover" src="/assets/vinyl.png"
                             data-src="{{ $record['cover'] }}"
                             alt="{{ $record['title'] }}">
                    </td>
                    <td>
                        {{ $record['artist'] . ' - ' . $record['title']  }}
                    </td>
                    <td>
                        <div class="btn-group btn-group-sm">
                            <a href="/basket/delete/{{ $record['id'] }}" class="btn btn-outline-secondary">-1</a>
                            <a href="/basket/add/{{ $record['id'] }}" class="btn btn-outline-secondary">+1</a>
                        </div>
                    </td>
                </tr>
            @endforeach
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td>
                    <p><a href="/basket/empty" class="btn btn-sm btn-outline-danger">Empty your basket</a></p>
                </td>
                <td>
                    <p><b>Total</b>:&nbsp;{{ Cart::getTotalPrice() }}</p>
                    <p><a href="/user/checkout" class="btn btn-sm btn-outline-success">Checkout</a></p>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
@endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

WARNING

  • When we loop over all our records inside the cart, the variable $record is a normal array, not a collection
    • To access a value inside this array, you can only use the default array syntax like $record['qty'] and not the collection syntax $record->qty!

REMARK

  • Everything works, except the Checkout link because we haven't provided a route yet

Basket is empty

Update the UI

  • Because Bootstrap does not provide any classes to format a table properly, we will first create some classes for giving elements a fixed width ourselves
  • Open resources/sass/_main.scss and generate some width-xxx classes
@for $i from 1 through 20 {
    // .width-10, .width-20, ... .width-200,
    .width-#{$i * 10} {
        width: #{$i * 10}px;
    }
}
1
2
3
4
5
6
  • The covers are much too big compared to the rest of the table
    • We add some .width-xxx classes to reduce the width of the quantity, price, cover and increase/decrease columns and give the remaining width to the record cells


 
 
 

 



<thead>
<tr>
    <th class="width-50">Qty</th>
    <th class="width-80">Price</th>
    <th class="width-80"></th>
    <th>Record</th>
    <th class="width-120"></th>
</tr>
</thead>
1
2
3
4
5
6
7
8
9

Reduce cover size

  • Add a script_after section to the page
    • Replace the dummy cover with the real cover
    • It's also nice if we vertically center all content inside the table cells with the Bootstrap class align-middle
      • We (vertically) center all the cells inside tbody, except inside the last row
@section('script_after')
    <script>
        $(function () {
            $('.cover').each(function () {
                $(this).attr('src', $(this).data('src'));
            });
            $('tbody tr:not(:last-child) td').addClass('align-middle');
        });
    </script>
@endsection
1
2
3
4
5
6
7
8
9
10

Show real cover and center data

  • Update the checkout link so that it's only visible if a user is logged in


 

 


<td>
<p><b>Total</b>:{{ Cart::getTotalPrice() }}</p>
@auth()
    <p><a href="/user/checkout" class="btn btn-sm btn-outline-success">Checkout</a></p>
@endauth
</td>
1
2
3
4
5
6
  • Show, just before the table, a warning/alert that you have to login before you can checkout
 
 
 
 
 




@guest()
    <div class="alert alert-primary">
        You must be <a href="/login"><b>logged in</b></a> to checkout
    </div>
@endguest
<div class="table-responsive">
    ...
</div>
1
2
3
4
5
6
7
8

User is not logged in

EXERCISE: Remove one record

  1. Add an extra button to remove a whole record (all copies) from the cart



 
 
 


    <div class="btn-group btn-group-sm">
        <a href="/basket/delete/{{ $record['id'] }}" class="btn btn-outline-secondary">-1</a>
        <a href="/basket/add/{{ $record['id'] }}" class="btn btn-outline-secondary">+1</a>
        <a href="/basket/remove/{{ $record['id'] }}" class="btn btn-outline-secondary">
            <i class="fas fa-trash-alt"></i>
        </a>
    </div>
1
2
3
4
5
6
7

Remove the whole record

  1. Add a new method removeRecord($item) to the Cart class to remove the whole record from the $records array
    (Don't forget to renew the ide-helper!)
  2. Add a new method removeRecordFromCart($id) to the BasketController
    • Select the record in the database
    • Pass it to the removeRecord() method inside the Cart class
    • Redirect back to the basket view
  3. Add the new route to routes/web.php
Last Updated: 5/4/2020, 1:23:12 PM