147 lines
6.0 KiB
PHP
147 lines
6.0 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Models\GameBet;
|
||
use App\Models\User;
|
||
use App\Models\UserAchievement;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Inertia\Inertia;
|
||
|
||
class TrophyController extends Controller
|
||
{
|
||
/**
|
||
* All available achievements with their unlock conditions (for display).
|
||
*/
|
||
public static array $definitions = [
|
||
'first_bet' => ['title' => 'First Bet', 'desc' => 'Place your very first bet.', 'icon' => '🎲'],
|
||
'first_win' => ['title' => 'First Win', 'desc' => 'Win your first game.', 'icon' => '🏆'],
|
||
'big_winner' => ['title' => 'Big Winner', 'desc' => 'Land a 10× or higher multiplier.', 'icon' => '💥'],
|
||
'high_roller' => ['title' => 'High Roller', 'desc' => 'Wager 100+ BTX in total.', 'icon' => '💎'],
|
||
'frequent_player' => ['title' => 'Frequent Player', 'desc' => 'Place 50+ bets.', 'icon' => '🔥'],
|
||
'hundred_bets' => ['title' => 'Centurion', 'desc' => 'Place 100+ bets.', 'icon' => '⚡'],
|
||
'vault_user' => ['title' => 'Vault Guardian', 'desc' => 'Make your first vault deposit.', 'icon' => '🔒'],
|
||
'vip_level2' => ['title' => 'Rising Star', 'desc' => 'Reach VIP Level 2.', 'icon' => '⭐'],
|
||
'vip_level5' => ['title' => 'Elite', 'desc' => 'Reach VIP Level 5.', 'icon' => '👑'],
|
||
'guild_member' => ['title' => 'Team Player', 'desc' => 'Join a guild.', 'icon' => '🛡️'],
|
||
'promo_user' => ['title' => 'Promo Hunter', 'desc' => 'Redeem your first promo code.', 'icon' => '🎁'],
|
||
];
|
||
|
||
/**
|
||
* Trophy room page — show user's achievements + locked ones.
|
||
*/
|
||
public function index(Request $request)
|
||
{
|
||
$user = Auth::user();
|
||
abort_unless($user, 403);
|
||
|
||
// Sync achievements before showing
|
||
$this->syncAchievements($user);
|
||
|
||
$unlocked = UserAchievement::where('user_id', $user->id)
|
||
->pluck('unlocked_at', 'achievement_key');
|
||
|
||
$achievements = [];
|
||
foreach (self::$definitions as $key => $def) {
|
||
$achievements[] = [
|
||
'key' => $key,
|
||
'title' => $def['title'],
|
||
'description' => $def['desc'],
|
||
'icon' => $def['icon'],
|
||
'unlocked' => isset($unlocked[$key]),
|
||
'unlocked_at' => isset($unlocked[$key]) ? $unlocked[$key]->toIso8601String() : null,
|
||
];
|
||
}
|
||
|
||
// Sort: unlocked first, then locked
|
||
usort($achievements, fn($a, $b) => ($b['unlocked'] <=> $a['unlocked']));
|
||
|
||
return Inertia::render('Trophy', [
|
||
'achievements' => $achievements,
|
||
'total' => count(self::$definitions),
|
||
'unlocked' => $unlocked->count(),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Trophy room for a specific user (public profiles only).
|
||
*/
|
||
public function show(Request $request, string $username)
|
||
{
|
||
$user = User::where('username', $username)->firstOrFail();
|
||
|
||
// Only show trophies for public profiles (or own profile)
|
||
if (!$user->is_public && Auth::id() !== $user->id) {
|
||
abort(403, 'This profile is private.');
|
||
}
|
||
|
||
$this->syncAchievements($user);
|
||
|
||
$unlocked = UserAchievement::where('user_id', $user->id)
|
||
->pluck('unlocked_at', 'achievement_key');
|
||
|
||
$achievements = [];
|
||
foreach (self::$definitions as $key => $def) {
|
||
$achievements[] = [
|
||
'key' => $key,
|
||
'title' => $def['title'],
|
||
'description' => $def['desc'],
|
||
'icon' => $def['icon'],
|
||
'unlocked' => isset($unlocked[$key]),
|
||
'unlocked_at' => isset($unlocked[$key]) ? $unlocked[$key]->toIso8601String() : null,
|
||
];
|
||
}
|
||
|
||
usort($achievements, fn($a, $b) => ($b['unlocked'] <=> $a['unlocked']));
|
||
|
||
return Inertia::render('Trophy', [
|
||
'achievements' => $achievements,
|
||
'total' => count(self::$definitions),
|
||
'unlocked' => $unlocked->count(),
|
||
'profileUser' => ['username' => $user->username, 'avatar' => $user->avatar],
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* Check and unlock achievements for the given user.
|
||
*/
|
||
public function syncAchievements(\App\Models\User $user): void
|
||
{
|
||
$bets = GameBet::where('user_id', $user->id);
|
||
$betCount = $bets->count();
|
||
$totalWager = $bets->sum('wager_amount');
|
||
$maxMulti = $bets->max('payout_multiplier') ?? 0;
|
||
$hasWin = $bets->where('payout_amount', '>', 0)->exists();
|
||
|
||
$toUnlock = [];
|
||
|
||
if ($betCount >= 1) $toUnlock[] = 'first_bet';
|
||
if ($hasWin) $toUnlock[] = 'first_win';
|
||
if ($maxMulti >= 10) $toUnlock[] = 'big_winner';
|
||
if ($totalWager >= 100) $toUnlock[] = 'high_roller';
|
||
if ($betCount >= 50) $toUnlock[] = 'frequent_player';
|
||
if ($betCount >= 100) $toUnlock[] = 'hundred_bets';
|
||
if ($user->vip_level >= 2) $toUnlock[] = 'vip_level2';
|
||
if ($user->vip_level >= 5) $toUnlock[] = 'vip_level5';
|
||
if ($user->guildMember()->exists()) $toUnlock[] = 'guild_member';
|
||
|
||
// Vault usage
|
||
if (\App\Models\WalletTransfer::where('user_id', $user->id)->where('type', 'deposit')->exists()) {
|
||
$toUnlock[] = 'vault_user';
|
||
}
|
||
// Promo usage
|
||
if (\App\Models\PromoUsage::where('user_id', $user->id)->exists()) {
|
||
$toUnlock[] = 'promo_user';
|
||
}
|
||
|
||
foreach ($toUnlock as $key) {
|
||
UserAchievement::firstOrCreate(
|
||
['user_id' => $user->id, 'achievement_key' => $key],
|
||
['unlocked_at' => now()]
|
||
);
|
||
}
|
||
}
|
||
}
|