# User: order history
- On the Order history page, a user can view all the orders the user has ever placed
REMARKS
- The history is a static view with no interaction, so we can use a simple Blade view for this page or a Livewire component
- We will use a Livewire component for this page, so we can easily add more functionality later on if we want to
# Preparation
# Create a Histories component
- Create a new Livewire component with the terminal command
php artisan make:livewire User/History
- app/Http/Livewire/User/History.php (the component class)
- resources/views/livewire/user/history.blade.php (the component view)
- Open the component class and change the layout to
layouts.vinylshop
class History extends Component { public function render() { return view('livewire.user.history') ->layout('layouts.vinylshop', [ 'description' => 'Your order history', 'title' => 'Your order history', ]); } }
Copied!
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# Add a new route
- Add a new get-route for the History to the routes/web.php file
- Update the navigation menu in resources/views/components/layouts/nav-bar.blade.php
routes/web.php
resources/views/livewire/layout/nav-bar.blade.php
- Add the route in the new user group
- Protected the group with the
auth
andactive
middleware, so only logged-in, active users can access this routes- The URL is user/history (prefix is already set to user)
- The view is user/history
- The route name is user.history (the group name is already set to user.)
Route::view('/', 'home')->name('home'); Route::get('shop', Shop::class)->name('shop'); Route::view('contact', 'contact')->name('contact'); Route::get('basket', Basket::class)->name('basket'); Route::view('playground', 'playground')->name('playground'); Route::get('itunes', Itunes::class)->name('itunes'); Route::middleware(['auth', 'active'])->prefix('user')->name('user.')->group(function () { Route::redirect('/', '/user/history'); Route::get('history', History::class)->name('history'); }); Route::middleware(['auth', 'active', 'admin'])->prefix('admin')->name('admin.')->group(function () { Route::redirect('/', '/admin/records'); Route::get('genres', Genres::class)->name('genres'); Route::get('records_old', [RecordController::class, 'index'])->name('records.old'); Route::get('records', Records::class)->name('records'); Route::get('users/basic', UsersBasic::class)->name('users.basic'); Route::get('users/advanced', UsersAdvanced::class)->name('users.advanced'); Route::get('users/expert', UsersExpert::class)->name('users.expert'); Route::get('covers', Covers::class)->name('covers'); }); ...
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Basic scaffolding for view
- Open resources/views/livewire/user/history.blade.php and replace the content with the following code:
livewire/user/history.blade.php
result
<div class="grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-8 items-start"> <div class="flex flex-col bg-white border border-gray-300 shadow-md rounded-lg overflow-hidden"> <div class="p-2 bg-gray-100 border-b border-b-gray-300"> <p class="font-bold">Order date: <span class="font-normal">...</span></p> </div> <div class="p-2 flex-1 flex gap-4"> <img src="{{ asset('storage/covers/no-cover.png') }}" alt="" class="w-28 h-28 object-cover"> <div class="flex-1 flex flex-col"> <p class="font-medium">Artist</p> <p class="italic">Title</p> <p class="font-sm text-gray-400">Quantity: ...</p> <p class="font-sm text-gray-400">Price: € ...</p> </div> </div> <div class="p-2 bg-gray-100 border-t border-t-gray-300"> <p class="font-bold">Total price: <span class="font-normal"> € ...</span></p> </div> </div> </div>
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Orders overview
- The only thing we need to do is get all the orders with the orderlines and send them to the view
Livewire/User/History.php
livewire/user/history.blade.php
result (no orders)
result (with orders)
- Line 5: get all the orders for the current user
- Line 6: include the orderlines for each order
- Line 7: order the orders by the date (the newest first)
- Line 9: compact the orders and send them to the view
class History extends Component { public function render() { $orders = Order::where('user_id', auth()->id()) ->with('orderlines') ->orderByDesc('created_at') ->get(); return view('livewire.user.history', compact('orders')) ->layout('layouts.vinylshop', [ 'description' => 'Your order history', 'title' => 'Your order history', ]); } }
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Get the cover image
- We don't have the cover image yet, so we need to get it from the
mb_id
of the orderline - Open the app/Models/Orderline.php model and make a new attribute
cover
and add it to the$appends
array
class Orderline extends Model { use HasFactory; ... /** Add additional attributes ... */ protected function cover(): Attribute { return Attribute::make( get: function ($value, $attributes) { return Storage::disk('public')->exists('covers/' . $attributes['mb_id'] . '.jpg') ? Storage::url('covers/' . $attributes['mb_id'] . '.jpg') : Storage::url('covers/no-cover.png'); }, ); } protected $appends = ['cover']; ... }
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- Replace the
img
tag in the resources/views/livewire/user/history.blade.php view with the$orderline->cover
attribute:- Replace de src attribute with
$orderline->cover
- Replace de src attribute with
<img src="{{ $orderline->cover }}" alt="" class="w-28 h-28 object-cover">
Copied!
1