@extends('layouts.app') @section('title', 'Dashboard - GIGAX ARENA') @section('page_title', 'Visão Geral') @section('content') @php use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Carbon; $user = Auth::user(); if (!$user) { $sid = (int) session('user_id', 0); if ($sid > 0) { try { $user = \App\Models\User::find($sid); } catch (\Throwable $e) { $user = null; } } } $userId = (int) ($user->id ?? session('user_id', 0)); if ($userId > 0) { try { $fresh = DB::table('users')->where('id', $userId)->first(); if ($fresh) $user = $fresh; } catch (\Throwable $e) {} } $name = $kruxName ?? $user->nickname ?? $user->name ?? session('user_nickname', 'Jogador'); $go = static fn(string $route, string $fallback) => Route::has($route) ? route($route) : url($fallback); // ESTATÍSTICAS REAIS: histórico finalizado + stats do próprio jogador. $matches = 0; $wins = 0; $losses = 0; $kills = 0; $deaths = 0; $assists = 0; $headshots = 0; try { if ($userId > 0 && Schema::hasTable('mix_training_history') && Schema::hasTable('mix_training_player_stats')) { $st = DB::selectOne("\n SELECT\n COUNT(*) AS matches,\n SUM(CASE WHEN th.winning_team = ps.team THEN 1 ELSE 0 END) AS wins,\n SUM(CASE WHEN th.winning_team <> ps.team THEN 1 ELSE 0 END) AS losses,\n SUM(ISNULL(ps.kills,0)) AS kills,\n SUM(ISNULL(ps.deaths,0)) AS deaths,\n SUM(ISNULL(ps.assists,0)) AS assists\n FROM mix_training_history th\n INNER JOIN mix_training_player_stats ps ON ps.match_id = th.match_id\n WHERE ps.user_id = ?\n ", [$userId]); $matches=(int)($st->matches??0); $wins=(int)($st->wins??0); $losses=(int)($st->losses??0); $kills=(int)($st->kills??0); $deaths=(int)($st->deaths??0); $assists=(int)($st->assists??0); } else { $matches=(int)($user->total_matches??0); $wins=(int)($user->wins??0); $losses=(int)($user->losses??0); $kills=(int)($user->kills??0); $deaths=(int)($user->deaths??0); $assists=(int)($user->assists??0); } $headshots=(int)($user->headshots??0); } catch (\Throwable $e) {} $winRateValue = $matches > 0 ? (($wins/max(1,$matches))*100) : 0; $winRate = number_format($winRateValue,1,',','.') . '%'; $kd = $deaths > 0 ? number_format($kills/$deaths,2,'.','') : number_format($kills,2,'.',''); $hsRate = $kills > 0 ? number_format(($headshots/$kills)*100,1,',','.') . '%' : '0%'; // XP/nível vêm de uma única fonte; conta nova ou reset = nível 1 / 0 XP. $level = 1; $xpValue = 0; $xpMaxValue = 10000; try { if ($userId > 0 && Schema::hasTable('gx_player_experience')) { $xpRow = DB::table('gx_player_experience')->where('user_id',$userId)->first(); if ($xpRow) { $level=(int)($xpRow->level??1); $xpValue=(int)($xpRow->monthly_xp??0); } } else { $level=(int)($user->skill_level??1); } } catch (\Throwable $e) {} $level=max(1,$level); $xpValue=max(0,$xpValue); $xpPercent=$xpMaxValue>0?min(100,max(0,($xpValue/$xpMaxValue)*100)):0; // Presença real do AC e versão publicada. $publishedAcVersion='—'; try { $vf=public_path('Atualizacoes/versao.txt'); if (is_file($vf)) $publishedAcVersion=trim((string)file_get_contents($vf)) ?: '—'; } catch (\Throwable $e) {} $acOnline=false; $heartbeatOk=false; $liveAcPlayers=collect(); $onlineCount=0; try { $acSummary=app(\App\Services\GigaxAcPresenceService::class)->summary(); $liveAcPlayers=collect($acSummary['players']??[])->take(5)->values(); $onlineCount=(int)($acSummary['online_count']??$liveAcPlayers->count()); $meAc=$liveAcPlayers->first(fn($p)=>(int)($p->uid??$p->user_id??0)===$userId); $acOnline=(bool)($verificationSummary['ac_online']??($meAc?true:false)); $heartbeatOk=(bool)($verificationSummary['heartbeat_ok']??$acOnline); } catch (\Throwable $e) { $acOnline=(bool)($verificationSummary['ac_online']??false); $heartbeatOk=(bool)($verificationSummary['heartbeat_ok']??false); } // Fila: apenas filas waiting e posição do jogador atual. $queueCount=0; $queuePosition=0; $queueMode='5v5 Competitivo'; try { if (Schema::hasTable('mix_queue_players') && Schema::hasTable('mix_queues')) { $queueCount=(int)DB::table('mix_queue_players as qp')->join('mix_queues as q','q.id','=','qp.queue_id')->where('q.status','waiting')->count(); if ($userId>0) { $uq=DB::table('mix_queue_players as qp')->join('mix_queues as q','q.id','=','qp.queue_id')->where('q.status','waiting')->where('qp.user_id',$userId)->select('qp.position')->orderByDesc('qp.id')->first(); $queuePosition=(int)($uq->position??0); } } } catch (\Throwable $e) {} $queueEta=$queueCount>=10?'Pronta':'Aguardando'; // Partida atual: SOMENTE se este jogador participa dela. $current=null; try { if ($userId>0 && Schema::hasTable('mix_training_matches') && Schema::hasTable('mix_training_participants')) { $current=DB::table('mix_training_matches as m') ->join('mix_training_participants as p','p.training_match_id','=','m.id') ->where('p.user_id',$userId)->whereNull('p.left_at') ->whereIn('m.status',['active','in_progress','playing','ready_check','veto']) ->select('m.*')->orderByDesc('m.id')->first(); } } catch (\Throwable $e) {} // Últimas partidas: SOMENTE histórico oficial do jogador logado. $recentMatches=collect(); try { if ($userId>0 && Schema::hasTable('mix_training_history') && Schema::hasTable('mix_training_player_stats')) { $recentMatches=collect(DB::select("\n SELECT TOP 5\n th.match_id, th.map_played, th.completed_at, th.winning_team,\n ps.team, ISNULL(ps.kills,0) kills, ISNULL(ps.deaths,0) deaths, ISNULL(ps.assists,0) assists,\n CASE WHEN th.winning_team = ps.team THEN 'win' ELSE 'loss' END result\n FROM mix_training_history th\n INNER JOIN mix_training_player_stats ps ON ps.match_id=th.match_id\n WHERE ps.user_id=?\n ORDER BY th.completed_at DESC\n ",[$userId])); if (Schema::hasTable('gx_xp_transactions')) { $recentMatches=$recentMatches->map(function($m) use($userId){ try { $m->xp=(int)DB::table('gx_xp_transactions')->where('user_id',$userId)->where('reference_id',(string)$m->match_id)->sum('xp'); } catch(\Throwable $e){ $m->xp=0; } return $m; }); } } } catch (\Throwable $e) {} // Ranking mensal real: só entra quem possui XP mensal > 0. Sem atividade = ranking vazio, não ranking falso por ID. $ranking=collect(); try { if (Schema::hasTable('gx_player_experience') && Schema::hasTable('users')) { $ranking=DB::table('gx_player_experience as x')->join('users as u','u.id','=','x.user_id') ->where('x.monthly_xp','>',0)->orderByDesc('x.monthly_xp')->orderBy('u.nickname') ->limit(5)->get(['u.id as user_id','u.nickname','u.avatar_url','x.monthly_xp as score','x.synced_wins as wins']); } } catch (\Throwable $e) {} // Youtubers cadastrados pelo painel Admin. Se a tabela ainda não existir, mantém compatibilidade com dados antigos. $streams=collect(); try { if (Schema::hasTable('gigax_youtubers')) { $streams=DB::table('gigax_youtubers') ->where('active',1) ->where('is_live',1) ->orderBy('sort_order') ->orderBy('channel_name') ->limit(4) ->get(); } else { $streams=collect($youtubeLives??$liveStreams??$streamersLive??[])->take(4); } } catch (\Throwable $e) { $streams=collect($youtubeLives??$liveStreams??$streamersLive??[])->take(4); } $shortcutItems=[ ['⚡','Jogar agora','Entrar na fila MIX',$go('lobby.index','/lobby'),'orange'], ['⚔','Partidas','Ver minhas partidas',$go('partidas','/partidas'),'red'], ['▦','Rankings','Ver classificação',$go('ranking','/ranking'),'blue'], ['●','Meu Perfil','Editar perfil',$go('profile','/profile'),'purple'], ['🛒','Loja','Ver itens',$go('loja','/loja'),'purple'], ['🏆','Torneios','Campeonatos',$go('tournaments.index','/tournaments'),'gold'], ]; $avatarUrl=\App\Support\GigaxAvatar::fromUser($user) ?: \App\Support\GigaxAvatar::url(session('user_avatar')); $avatarInitial=mb_strtoupper(mb_substr(trim((string)$name),0,1)); @endphp
COMUNIDADE FORTE