feat: add member order history page with detailed order summaries and navigation.

This commit is contained in:
Yoga Pangestu 2026-01-06 20:59:42 +07:00
parent ca92fc9089
commit bebc5be5a2
6 changed files with 135 additions and 2 deletions

View File

@ -14,7 +14,7 @@ class MyVouchers extends Component
{
public array $myVouchers = [];
public function mount()
public function mount(): void
{
$this->myVouchers = auth()->user()->vouchers()
->withPivot('quantity', 'created_at')

View File

@ -0,0 +1,49 @@
<?php
namespace App\Livewire\Member;
use App\Models\Order;
use Illuminate\Contracts\View\View;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Title('Riwayat Pesanan')]
#[Layout('components.layouts.member')]
class OrderHistory extends Component
{
public array $orders = [];
public function mount(): void
{
$this->orders = Order::where('customer_id', auth()->user()->customer->id)
->with(['items.orderable'])
->latest()
->get()
->map(function ($order) {
$order->status_color = $order->status->color();
$order->status_label = $order->status->label();
$order->formatted_created_at = formatDateLocalized($order->created_at);
$order->formatted_total = formatCurrencyNumber($order->total, 'Rp');
$order->total_items_count = $order->items->count();
$order->preview_items = $order->items->take(2)->map(function ($item) {
return [
'name' => $item->orderable->name ?? 'Unknown Item',
'quantity_label' => ! empty($item->quality) ? $item->quality : 'x'.$item->quantity,
];
});
$order->remaining_items_count = max(0, $order->items->count() - 2);
return $order;
})
->toArray();
}
public function render(): View
{
return view('livewire.member.order-histories', [
'pageTitle' => 'Riwayat Pesanan',
'pageDescription' => 'Lihat riwayat pesanan dan status pembayaran Anda.',
]);
}
}

View File

@ -16,6 +16,9 @@ class="bg-zinc-50 dark:bg-zinc-900 border-r rtl:border-r-0 rtl:border-l border-z
<flux:navlist.item icon="ticket" href="{{ route('member.my_vouchers') }}"
:current="request()->routeIs('member.my_vouchers')" wire:navigate>
Voucher Saya</flux:navlist.item>
<flux:navlist.item icon="shopping-bag" href="{{ route('member.order_history') }}"
:current="request()->routeIs('member.order_history')" wire:navigate>
Riwayat Pesanan</flux:navlist.item>
<flux:navlist.item icon="check-badge" href="{{ route('member.redeem_point') }}"
:current="request()->routeIs('member.redeem_point')" wire:navigate>
Penukaran Poin</flux:navlist.item>

View File

@ -0,0 +1,79 @@
<flux:main>
<flux:heading size="xl" level="1">{{ $pageTitle }}</flux:heading>
<flux:text class="mb-6 mt-2 text-base">{{ $pageDescription }}</flux:text>
@if (empty($orders))
<flux:card class="text-center py-12">
<div class="flex flex-col items-center justify-center">
<flux:icon.shopping-bag variant="outline" class="size-16 text-zinc-400 mb-4" />
<flux:heading size="lg" class="mb-2">Belum Ada Pesanan</flux:heading>
<flux:text class="text-zinc-500 mb-6">
Anda belum melakukan pemesanan apapun. Mulai belanja sekarang!
</flux:text>
</div>
</flux:card>
@else
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@foreach ($orders as $order)
<flux:card class="relative overflow-hidden flex flex-col h-full">
{{-- Badge Status --}}
<div class="absolute top-4 right-4">
<flux:badge color="{{ $order['status_color'] }}" size="sm">
{{ $order['status_label'] }}
</flux:badge>
</div>
{{-- Order Header --}}
<div class="mb-4 flex-1">
<flux:heading size="lg" class="mb-1">Order #{{ $order['invoice_number'] }}
</flux:heading>
{{-- Date --}}
<div class="flex items-center gap-2 mb-4 text-zinc-500 dark:text-zinc-400">
<flux:icon.calendar class="size-4" />
<flux:text class="text-sm">
{{ $order['formatted_created_at'] }}
</flux:text>
</div>
{{-- Items Count --}}
<div class="flex items-center gap-2 mb-2">
<flux:icon.shopping-bag class="size-4 text-zinc-500" />
<flux:text class="text-sm">
{{ $order['total_items_count'] }} Produk
</flux:text>
</div>
{{-- Total Amount --}}
<div class="flex items-center gap-2">
<flux:icon.credit-card class="size-4 text-zinc-500" />
<flux:text class="text-lg font-semibold text-zinc-900 dark:text-white">
{{ $order['formatted_total'] }}
</flux:text>
</div>
</div>
<flux:separator class="my-3" />
{{-- Items Preview --}}
<div class="space-y-2">
<flux:text class="text-xs font-medium uppercase tracking-wider text-zinc-500">Ringkasan Pesanan
</flux:text>
@foreach ($order['preview_items'] as $item)
<div class="flex justify-between items-start text-sm">
<span class="truncate pr-2 text-zinc-700 dark:text-zinc-300">{{ $item['name'] }}</span>
<span
class="text-xs text-zinc-500 whitespace-nowrap">{{ $item['quantity_label'] }}</span>
</div>
@endforeach
@if ($order['remaining_items_count'] > 0)
<flux:text class="text-xs text-zinc-400 italic">
+{{ $order['remaining_items_count'] }} item lainnya
</flux:text>
@endif
</div>
</flux:card>
@endforeach
</div>
@endif
</flux:main>

View File

@ -299,7 +299,7 @@
<flux:input.group>
<flux:input.group.prefix>Rp</flux:input.group.prefix>
<flux:input placeholder="10.000" x-mask:dynamic="$money($input, ',')"
wire:model="form.discount" autocomplete="off" />
wire:model.live="form.discount" autocomplete="off" />
</flux:input.group>
</flux:field>
</div>

View File

@ -2,6 +2,7 @@
use App\Livewire\Member\Membership;
use App\Livewire\Member\MyVouchers;
use App\Livewire\Member\OrderHistory;
use App\Livewire\Member\Overview;
use App\Livewire\Member\RedeemPoint;
use App\Livewire\Member\Referral;
@ -16,6 +17,7 @@
Route::get('memberships', Membership::class)->name('membership');
Route::get('my-vouchers', MyVouchers::class)->name('my_vouchers');
Route::get('order-histories', OrderHistory::class)->name('order_history');
Route::get('redeem-points', RedeemPoint::class)->name('redeem_point');
Route::get('referrals', Referral::class)->name('referral');
Route::get('settings', Account::class)->name('setting');