with(['user.customer.orders.items']) ->orderByDesc('total_spending') ->first(); if (! $topMembership || ! $topMembership->user || ! $topMembership->user->customer) { return null; } $customer = $topMembership->user->customer; $orders = $customer->orders; $totalOrders = $orders->count(); // Sum items $totalPerfume = $orders->flatMap(fn ($order) => $order->items->where('orderable_type', Perfume::class))->sum('quantity'); $totalProduct = $orders->flatMap(fn ($order) => $order->items->where('orderable_type', Product::class))->sum('quantity'); $totalBottle = $orders->flatMap(fn ($order) => $order->items->where('orderable_type', Bottle::class))->sum('quantity'); // Sum total $subtotal = $orders->sum('subtotal'); $totalDiscount = $orders->sum('discount'); $grandTotal = $orders->sum('total'); return [ 'name' => $customer->name, 'spending' => formatCurrencyNumber($topMembership->total_spending, 'Rp'), 'total_orders' => formatCurrencyNumber($totalOrders), 'items' => [ 'total_perfume' => formatCurrencyNumber($totalPerfume), 'total_product' => formatCurrencyNumber($totalProduct), 'total_bottle' => formatCurrencyNumber($totalBottle), ], 'total' => [ 'subtotal' => formatCurrencyNumber($subtotal, 'Rp'), 'discount' => formatCurrencyNumber($totalDiscount, 'Rp'), 'grand_total' => formatCurrencyNumber($grandTotal, 'Rp'), ], ]; } public function create(): void { $this->canOrAbort('create tier'); $this->form->store(); // Reorder the entire tier chain to ensure proper max_spending TierModel::reorderTierChain(); $this->toast('Tier berhasil ditambahkan.'); Flux::modals()->close(); } public function update(): void { $this->canOrAbort('update tier'); $oldMinSpending = $this->form->tier->min_spending; $newMinSpending = parseRupiahToInt($this->form->min_spending); $this->form->update(); // If min_spending changed, reorder the entire tier chain if ($oldMinSpending !== $newMinSpending) { TierModel::reorderTierChain(); } $this->toast('Tier berhasil diperbarui.'); Flux::modals()->close(); } public function delete(TierModel $tier): void { $this->canOrAbort('delete tier'); // Validate if tier can be deleted $canDelete = TierModel::canDeleteTier($tier->id); if (! $canDelete['can_delete']) { $this->toast($canDelete['message'], 'Gagal', 'danger'); return; } $tier->delete(); // Reorder tier chain after deletion to ensure proper max_spending TierModel::reorderTierChain(); $this->toast('Tier berhasil dihapus.'); Flux::modals()->close(); } #[On('modal:open')] public function openModal(string $method, string $modalTitle, ?string $id = null): void { $this->resetValidation(); $this->resetErrorBag(); $this->method = $method; $this->modalTitle = $modalTitle; $id && $this->form->setTier(TierModel::byHashOrFail($id)); } public function render(): View { $tiers = TierModel::withCount('memberships') ->orderBy('min_spending', 'asc') ->get() ->map(fn (TierModel $tier) => [ 'id' => $tier->id, 'hash' => $tier->hash, 'name' => $tier->name, 'min_spending' => formatCurrencyNumber($tier->min_spending, 'Rp'), 'max_spending' => $tier->max_spending ? formatCurrencyNumber($tier->max_spending, 'Rp') : 'Tak terbatas', 'total_members' => formatCurrencyNumber($tier->memberships_count), 'top_member' => $this->getTopMemberStats($tier->id), ]) ->toArray(); return view('livewire.studio.loyalty.tiers', [ 'pageTitle' => 'Tier', 'tiers' => $tiers, ]); } }