189 lines
5.9 KiB
PHP
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',
|
|
]);
|
|
}
|
|
}
|