135 lines
4.0 KiB
PHP
135 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Member;
|
|
|
|
use App\Enums\PointRecordType;
|
|
use App\Enums\RedemptionStatus;
|
|
use App\Models\Redemption;
|
|
use App\Models\Reward;
|
|
use App\Traits\Components\WithConfirmation;
|
|
use App\Traits\Components\WithToast;
|
|
use Flux\Flux;
|
|
use Illuminate\Contracts\View\View;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Attributes\Title;
|
|
use Livewire\Component;
|
|
|
|
#[Title('Hadiah')]
|
|
#[Layout('components.layouts.member')]
|
|
class RedeemPoint extends Component
|
|
{
|
|
use WithConfirmation, WithToast;
|
|
|
|
public array $rewards = [];
|
|
|
|
public array $userRedemptions = [];
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->rewards = Reward::show()
|
|
->active()
|
|
->orderBy('points')
|
|
->get()
|
|
->map(function (Reward $reward) {
|
|
$reward->thumbnail = $reward->getFirstMediaUrl('thumbnail');
|
|
$reward->category_label = $reward->category->label();
|
|
|
|
return $reward;
|
|
})
|
|
->toArray();
|
|
|
|
$this->userRedemptions = Redemption::with('reward')
|
|
->where('user_id', auth()->id())
|
|
->latest()
|
|
->get()
|
|
->map(function (Redemption $redemption) {
|
|
$redemption->status_label = $redemption->status->label();
|
|
$redemption->status_color = $redemption->status->color();
|
|
|
|
return $redemption;
|
|
})
|
|
->toArray();
|
|
}
|
|
|
|
public function redeem(Reward $reward): void
|
|
{
|
|
$user = auth()->user();
|
|
$membership = $user->membership;
|
|
|
|
if ($membership->reward_points < $reward->points) {
|
|
$this->toast('Poin Anda tidak cukup untuk menukarkan hadiah ini.', 'Gagal', 'danger');
|
|
|
|
Flux::modals()->close();
|
|
|
|
return;
|
|
}
|
|
|
|
if ($reward->stock !== null && $reward->stock <= 0) {
|
|
$this->toast('Stok hadiah ini sudah habis.', 'Gagal', 'danger');
|
|
Flux::modals()->close();
|
|
|
|
return;
|
|
}
|
|
|
|
$redemption = DB::transaction(function () use ($user, $membership, $reward) {
|
|
// Deduct points from membership
|
|
$membership->decrement('reward_points', $reward->points);
|
|
|
|
// Create point record
|
|
$user->pointRecords()->create([
|
|
'change' => $reward->points,
|
|
'type' => PointRecordType::REWARD,
|
|
'is_addition' => false,
|
|
'description' => Str::limit("Redeem: {$reward->name}", 50),
|
|
]);
|
|
|
|
// Create redemption
|
|
$redemption = Redemption::create([
|
|
'user_id' => $user->id,
|
|
'reward_id' => $reward->id,
|
|
'code' => 'RD-'.Str::upper(Str::random(8)),
|
|
'points_spent' => $reward->points,
|
|
'status' => RedemptionStatus::WAITING_PICKUP,
|
|
'expires_at' => now()->addWeek(),
|
|
]);
|
|
|
|
// Decrement stock if applicable
|
|
if ($reward->stock !== null) {
|
|
$reward->decrement('stock');
|
|
}
|
|
|
|
return $redemption;
|
|
});
|
|
|
|
// Update rewards list in real-time
|
|
$this->rewards = collect($this->rewards)->map(function ($item) use ($reward) {
|
|
if ($item['id'] === $reward->getRouteKey() && $item['stock'] !== null) {
|
|
$item['stock']--;
|
|
}
|
|
|
|
return $item;
|
|
})->toArray();
|
|
|
|
// Update user redemptions history in real-time
|
|
$redemption->load('reward');
|
|
array_unshift($this->userRedemptions, [
|
|
...$redemption->toArray(),
|
|
'status_label' => $redemption->status->label(),
|
|
'status_color' => $redemption->status->color(),
|
|
]);
|
|
|
|
$this->toast('Hadiah berhasil ditukarkan! Silakan cek tab Riwayat untuk melihat kode penukaran Anda.');
|
|
|
|
Flux::modals()->close();
|
|
}
|
|
|
|
public function render(): View
|
|
{
|
|
return view('livewire.member.rewards', [
|
|
'pageTitle' => 'Penukaran Poin',
|
|
]);
|
|
}
|
|
}
|