From 33d11cedea5ba5e3f1096b5d0648d04240818582 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Mon, 5 Jan 2026 20:11:06 +0700 Subject: [PATCH] feat: implement member referral system including code generation, usage tracking, and UI integration. --- app/Livewire/Member/Referral.php | 55 +++++++++++++ app/Models/ReferralCode.php | 5 +- .../sections/ui/member/_sidebar.blade.php | 3 + .../livewire/member/memberships.blade.php | 58 ++++++-------- .../views/livewire/member/overview.blade.php | 3 +- .../views/livewire/member/referral.blade.php | 80 +++++++++++++++++++ routes/pages/member.php | 3 +- 7 files changed, 167 insertions(+), 40 deletions(-) create mode 100644 app/Livewire/Member/Referral.php create mode 100644 resources/views/livewire/member/referral.blade.php diff --git a/app/Livewire/Member/Referral.php b/app/Livewire/Member/Referral.php new file mode 100644 index 0000000..c670293 --- /dev/null +++ b/app/Livewire/Member/Referral.php @@ -0,0 +1,55 @@ +user(); + $referralCode = $user->referralCode; + + $usages = ReferralUsage::with(['user', 'user.customer', 'user.membership']) + ->where('referral_code_id', $referralCode->id) + ->latest() + ->get() + ->map(function ($usage) { + $spending = $usage->user?->membership?->total_spending ?? 0; + $progress = min(100, ($spending / self::TARGET_SPENDING) * 100); + $isRewardEarned = $spending >= self::TARGET_SPENDING; + + return [ + 'name' => $usage->user?->customer?->name ?? 'Perfumers', + 'joined_at' => $usage->created_at, + 'spending' => $spending, + 'progress' => $progress, + 'is_reward_earned' => $isRewardEarned, + ]; + }); + + $message = 'Halo! Ayo bergabung di Yadi Parfum dan dapatkan keuntungan eksklusif. Gunakan kode referral saya: ' . ($referralCode?->code ?? '') . ' saat mendaftar! ' . url('/auth/register'); + $whatsappUrl = 'https://wa.me/?text=' . urlencode($message); + + return view('livewire.member.referral', [ + 'referralCode' => $referralCode, + 'usages' => $usages, + 'whatsappUrl' => $whatsappUrl, + 'targetSpending' => self::TARGET_SPENDING, + ]); + } +} diff --git a/app/Models/ReferralCode.php b/app/Models/ReferralCode.php index 0c7d9df..bf78259 100644 --- a/app/Models/ReferralCode.php +++ b/app/Models/ReferralCode.php @@ -5,7 +5,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\SoftDeletes; use Veelasky\LaravelHashId\Eloquent\HashableId; @@ -27,8 +26,8 @@ public function user(): BelongsTo return $this->belongsTo(User::class); } - public function referralUsage(): HasOne + public function usages(): \Illuminate\Database\Eloquent\Relations\HasMany { - return $this->hasOne(ReferralUsage::class); + return $this->hasMany(ReferralUsage::class); } } diff --git a/resources/views/components/sections/ui/member/_sidebar.blade.php b/resources/views/components/sections/ui/member/_sidebar.blade.php index ace0479..5e30ccd 100644 --- a/resources/views/components/sections/ui/member/_sidebar.blade.php +++ b/resources/views/components/sections/ui/member/_sidebar.blade.php @@ -16,6 +16,9 @@ class="bg-zinc-50 dark:bg-zinc-900 border-r rtl:border-r-0 rtl:border-l border-z Penukaran Poin + + Referral @can('view studio overview')
diff --git a/resources/views/livewire/member/memberships.blade.php b/resources/views/livewire/member/memberships.blade.php index f338acb..a27f9a2 100644 --- a/resources/views/livewire/member/memberships.blade.php +++ b/resources/views/livewire/member/memberships.blade.php @@ -2,44 +2,32 @@ {{ $pageTitle }}
- @if ($membership) -
- @foreach ($stats as $stat) -
-
- {{ $stat['title'] }} -
- {{ $stat['value'] }} - {{ $stat['description'] }} +
+ @foreach ($stats as $stat) +
+
+ {{ $stat['title'] }}
- @endforeach -
- -
-

Proses ke Tier {{ $nextTierName }}

-
-
- Sekarang: {{ $currentSpending }} - Target: {{ $nextTierSpending }} -
-
-
-
- {{ $progress }} % + {{ $stat['value'] }} + {{ $stat['description'] }}
+ @endforeach +
+ +
+

Proses ke Tier {{ $nextTierName }}

+
+
+ Sekarang: {{ $currentSpending }} + Target: {{ $nextTierSpending }} +
+
+
+
+ {{ $progress }} %
- @else -
- - - - Apa? Anda belum menjadi member, ayo sini daftar. - -
- @endif +
@assets diff --git a/resources/views/livewire/member/overview.blade.php b/resources/views/livewire/member/overview.blade.php index 5fb70af..e947424 100644 --- a/resources/views/livewire/member/overview.blade.php +++ b/resources/views/livewire/member/overview.blade.php @@ -18,7 +18,8 @@ Undang teman - Ambil Hadiah + Riwayat + Ambil Hadiah diff --git a/resources/views/livewire/member/referral.blade.php b/resources/views/livewire/member/referral.blade.php new file mode 100644 index 0000000..4cc8ffd --- /dev/null +++ b/resources/views/livewire/member/referral.blade.php @@ -0,0 +1,80 @@ + + Referral + Ajak temanmu bergabung dan dapatkan hadiah menarik dengan kode referralmu. + + +
+ +
+
+ Kode Referral Anda +
+
+ {{ $referralCode->code }} +
+ + + +
+
+
+ + Undang Teman via WhatsApp + +
+
+
+ + Riwayat Penggunaan + + @if ($usages->isEmpty()) + + @include('components.animations.lottie.not-found', [ + 'message' => 'Belum ada yang menggunakan kode referral Anda. Ayo ajak teman-temanmu!', + ]) + + @else +
+ @foreach ($usages as $usage) + +
+
+
+ {{ $usage['name'] }} + Bergabung pada + {{ formatDateLocalized($usage['joined_at'], 'd M Y') }} + +
+
+ @if ($usage['is_reward_earned']) + Target Tercapai + @else + Dalam Proses + @endif +
+
+ +
+
+ Akumulasi Belanja: {{ formatCurrencyNumber($usage['spending'], 'Rp') }} + + Target: {{ formatCurrencyNumber($targetSpending, 'Rp') }} +
+
+
+
+
+
+
+ @endforeach +
+ @endif +
+
+ +@assets + +@endassets diff --git a/routes/pages/member.php b/routes/pages/member.php index da5ec89..c3c86e8 100644 --- a/routes/pages/member.php +++ b/routes/pages/member.php @@ -3,8 +3,8 @@ use App\Livewire\Member\Membership; use App\Livewire\Member\Overview; use App\Livewire\Member\RedeemPoint; +use App\Livewire\Member\Referral; use App\Livewire\Member\Setting\Account; - use Illuminate\Support\Facades\Route; Route::middleware(['auth', 'verified']) @@ -15,5 +15,6 @@ Route::get('memberships', Membership::class)->name('membership'); Route::get('redeem-points', RedeemPoint::class)->name('redeem_point'); + Route::get('referrals', Referral::class)->name('referral'); Route::get('settings', Account::class)->name('setting'); });