parfum/app/Livewire/Studio/Loyalty/Tier/Index.php

191 lines
5.7 KiB
PHP

<?php
namespace App\Livewire\Studio\Loyalty\Tier;
use App\Livewire\Forms\Studio\Loyalty\TierForm;
use App\Models\Bottle;
use App\Models\Perfume;
use App\Models\Product;
use App\Models\Tier as TierModel;
use App\Traits\Authorization\WithAuthorization;
use App\Traits\Components\WithCloseModal;
use App\Traits\Components\WithConfirmation;
use App\Traits\Components\WithToast;
use App\Traits\Notification\WithSubscribeNotification;
use App\Traits\Utilities\WithUpdatedData;
use Flux\Flux;
use Illuminate\Contracts\View\View;
use Livewire\Attributes\On;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Title('Tier')]
class Index extends Component
{
use WithAuthorization, WithCloseModal, WithConfirmation, WithSubscribeNotification, WithToast, WithUpdatedData;
public array $tiers = [];
public TierForm $form;
public string $method = 'create';
public string $modalTitle = '';
public function mount(): void
{
$this->loadTiers();
}
#[On('data:tiersUpdated')]
public function loadTiers(): void
{
$this->tiers = TierModel::withCount('memberships')
->withCount('rewards')
->orderBy('min_points', 'asc')
->get()
->map(function ($tier) {
return [
'id' => $tier->id,
'hash' => $tier->hash,
'name' => $tier->name,
'min_points' => formatCurrencyNumber($tier->min_points),
'max_points' => formatCurrencyNumber($tier->max_points),
'total_members' => formatCurrencyNumber($tier->memberships_count),
'total_rewards' => $tier->rewards_count,
];
})
->toArray();
}
public function getTopMemberStats($tierId): ?array
{
$tier = TierModel::with(['memberships.user.customer.orders.items'])->find($tierId);
if (! $tier) {
return null;
}
$topMembership = $tier->memberships()
->with(['user.customer.orders.items'])
->orderByDesc('tier_points')
->first();
if (! $topMembership || ! $topMembership->user || ! $topMembership->user->customer) {
return null;
}
$orders = $topMembership->user->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' => $topMembership->user->customer->name,
'points' => formatCurrencyNumber($topMembership->tier_points),
'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_points
TierModel::reorderTierChain();
// Reload tiers to reflect the changes
$this->loadTiers();
$this->toast('Tier berhasil ditambahkan.');
Flux::modals()->close();
}
public function update(): void
{
$this->canOrAbort('update tier');
$oldMinPoints = $this->form->tier->min_points;
$newMinPoints = parseRupiahToInt($this->form->min_points);
$this->form->update();
// If min_points changed, reorder the entire tier chain
if ($oldMinPoints !== $newMinPoints) {
TierModel::reorderTierChain();
}
// Reload tiers to reflect any changes from reordering
$this->loadTiers();
$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_points
TierModel::reorderTierChain();
// Reload tiers to reflect the changes
$this->loadTiers();
$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
{
return view('livewire.studio.loyalty.tier.index', [
'pageTitle' => 'Tier',
]);
}
}