parfum/app/Livewire/Studio/Loyalty/Tier.php
2025-12-09 20:45:41 +07:00

189 lines
5.9 KiB
PHP

<?php
namespace App\Livewire\Studio\Loyalty;
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\Notification\WithSubscribeNotification;
use App\Traits\WithAuthorization;
use App\Traits\WithCloseModal;
use App\Traits\WithConfirmation;
use App\Traits\WithToast;
use App\Traits\WithUpdatedData;
use Flux\Flux;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
use Livewire\Attributes\On;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Title('Tier')]
class Tier extends Component
{
use WithAuthorization, WithCloseModal, WithConfirmation, WithSubscribeNotification, WithToast, WithUpdatedData;
public Collection $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::with(['rewards', 'memberships.user.customer.orders.items'])
->withCount(['memberships', 'rewards'])
->orderBy('min_points', 'asc')
->get()
->map(function ($tier) {
$topMembership = $tier->memberships()
->with(['user.customer.orders.items'])
->orderByDesc('tier_points')
->first();
$topMemberStats = null;
if ($topMembership && $topMembership->user && $topMembership->user->customer) {
$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');
$topMemberStats = [
'name' => $topMembership->user->customer->name,
'points' => currency($topMembership->tier_points),
'total_orders' => currency($totalOrders),
'items' => [
'total_perfume' => currency($totalPerfume),
'total_product' => currency($totalProduct),
'total_bottle' => currency($totalBottle),
],
'total' => [
'subtotal' => currency($subtotal, 'Rp'),
'discount' => currency($totalDiscount, 'Rp'),
'grand_total' => currency($grandTotal, 'Rp'),
],
];
}
$tier->top_member = $topMemberStats;
$tier->total_members = $tier->memberships_count;
$tier->total_rewards = $tier->rewards_count;
return $tier;
});
}
#[On('modal:open')]
public function openModal(string $method, string $modalTitle, ?string $id = null): void
{
$this->resetValidation();
$this->resetErrorBag();
$this->method = $method;
$this->modalTitle = $modalTitle;
if ($id) {
$this->form->setTier(TierModel::byHashOrFail($id));
}
}
public function create(): void
{
$this->canOrAbort('create tier');
$minPoints = (int) $this->form->min_points;
$maxPoints = (int) $this->form->max_points;
if (TierModel::isOverlap($minPoints, $maxPoints)) {
$this->toast('Range poin yang kamu masukkan bertabrakan dengan tier yang sudah ada.', 'Info', 'warning');
return;
}
$tier = $this->form->store();
// Add computed properties to the model
$tier->total_members = 0;
$tier->total_rewards = 0;
$tier->top_member = null;
// Add new tier to collection and sort
$this->tiers = $this->tiers->push($tier)->sortBy('min_points')->values();
$this->toast('Tier berhasil ditambahkan.');
Flux::modals()->close();
}
public function update(): void
{
$this->canOrAbort('update tier');
$tierId = $this->form->tier->id;
$minPoints = (int) $this->form->min_points;
$maxPoints = (int) $this->form->max_points;
if (TierModel::isOverlap($minPoints, $maxPoints, $tierId)) {
$this->toast('Range poin yang kamu masukkan bertabrakan dengan tier yang sudah ada.', 'Info', 'warning');
return;
}
$tier = $this->form->update();
// Update the tier in collection
$this->tiers = $this->tiers->map(function ($t) use ($tier) {
if ($t->hash === $tier->hash) {
$t->name = $tier->name;
$t->min_points = $tier->min_points;
$t->max_points = $tier->max_points;
}
return $t;
});
$this->toast('Tier berhasil diperbarui.');
Flux::modals()->close();
}
public function delete(TierModel $tier): void
{
$tier->delete();
// Remove tier from collection
$this->tiers = $this->tiers->filter(fn ($t) => $t->hash !== $tier->hash)->values();
$this->toast('Tier berhasil dihapus.');
Flux::modals()->close();
}
public function render(): View
{
return view('livewire.studio.loyalty.tier.index', [
'pageTitle' => 'Tier',
]);
}
}