fix: Resolve avatar display issues on chat and player pages

Chat page:
- Fix player lookup using player_name instead of player_id to avoid
  JavaScript number precision loss with 64-bit Steam IDs
- Update player filter dropdown to use names instead of IDs

Player page (Teammates):
- Construct full avatar URLs from hash when backend returns hash format
- Handle both full URLs and hashes with startsWith check

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-07 20:11:00 +01:00
parent 30b076bbec
commit b988d141dd
2 changed files with 26 additions and 17 deletions

View File

@@ -18,7 +18,7 @@
let searchQuery = $state('');
let showTeamChat = $state(true);
let showAllChat = $state(true);
let selectedPlayer = $state<number | null>(null);
let selectedPlayer = $state<string | null>(null);
// Check if text likely needs translation (contains non-ASCII or Cyrillic characters)
const mightNeedTranslation = (text: string): boolean => {
@@ -34,16 +34,15 @@
window.open(translateUrl, '_blank', 'width=800,height=600,noopener,noreferrer');
};
// Get unique players who sent messages
// Get unique players who sent messages (using player_name to avoid precision loss with player_id)
const messagePlayers = $derived(
chatData
? Array.from(new Set(chatData.messages.map((m) => m.player_id)))
.filter((playerId): playerId is number => playerId !== undefined)
.map((playerId) => {
const player = match.players?.find((p) => p.id === String(playerId));
? Array.from(new Set(chatData.messages.map((m) => m.player_name || `Player ${m.player_id}`)))
.filter((name): name is string => !!name)
.map((name) => {
const player = match.players?.find((p) => p.name === name);
return {
id: playerId,
name: player?.name || `Player ${playerId}`,
name,
team_id: player?.team_id || 0
};
})
@@ -56,7 +55,8 @@
? chatData.messages.filter((msg) => {
if (!showTeamChat && !msg.all_chat) return false;
if (!showAllChat && msg.all_chat) return false;
if (selectedPlayer !== null && msg.player_id !== selectedPlayer) return false;
const msgPlayerName = msg.player_name || `Player ${msg.player_id}`;
if (selectedPlayer !== null && msgPlayerName !== selectedPlayer) return false;
if (searchQuery && !msg.message.toLowerCase().includes(searchQuery.toLowerCase())) {
return false;
}
@@ -204,7 +204,7 @@
>
<option value={null}>All Players</option>
{#each messagePlayers as player}
<option value={player.id}>{player.name}</option>
<option value={player.name}>{player.name}</option>
{/each}
</select>
@@ -256,9 +256,8 @@
<!-- Messages -->
<div class="divide-y divide-white/5">
{#each messagesByRound[round] as message}
{@const player = match.players?.find((p) => p.id === String(message.player_id))}
{@const playerName =
message.player_name || player?.name || `Player ${message.player_id}`}
{@const playerName = message.player_name || `Player ${message.player_id}`}
{@const player = match.players?.find((p) => p.name === playerName)}
{@const playerAvatar = player?.avatar}
{@const teamId = player?.team_id || 0}
<div class="p-4 transition-colors hover:bg-white/5">

View File

@@ -1125,6 +1125,11 @@
<div class="space-y-3">
{#each metaStats.best_mates.slice(0, 5) as teammate}
{@const winRatePercent = (teammate.win_rate ?? 0) * 100}
{@const avatarUrl = teammate.player.avatar
? teammate.player.avatar.startsWith('http')
? teammate.player.avatar
: `https://avatars.steamstatic.com/${teammate.player.avatar}_full.jpg`
: null}
<a
href="/player/{teammate.player.steamid64}"
class="group flex items-center gap-3 rounded-lg bg-white/5 p-3 transition-all hover:bg-white/10"
@@ -1132,9 +1137,9 @@
<div
class="relative flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-white/10 bg-void"
>
{#if teammate.player.avatar}
{#if avatarUrl}
<img
src={teammate.player.avatar}
src={avatarUrl}
alt={teammate.player.name || 'Player'}
class="h-full w-full rounded-full object-cover"
onerror={(e) => {
@@ -1190,6 +1195,11 @@
<div class="space-y-3">
{#each metaStats.most_mates.slice(0, 5) as teammate}
{@const winRatePercent = (teammate.win_rate ?? 0) * 100}
{@const avatarUrl = teammate.player.avatar
? teammate.player.avatar.startsWith('http')
? teammate.player.avatar
: `https://avatars.steamstatic.com/${teammate.player.avatar}_full.jpg`
: null}
<a
href="/player/{teammate.player.steamid64}"
class="group flex items-center gap-3 rounded-lg bg-white/5 p-3 transition-all hover:bg-white/10"
@@ -1197,9 +1207,9 @@
<div
class="relative flex h-10 w-10 shrink-0 items-center justify-center rounded-full border border-white/10 bg-void"
>
{#if teammate.player.avatar}
{#if avatarUrl}
<img
src={teammate.player.avatar}
src={avatarUrl}
alt={teammate.player.name || 'Player'}
class="h-full w-full rounded-full object-cover"
onerror={(e) => {