feat: Add VAC/ban status column to match scoreboard
Add per-player VAC and game ban status display in match details scoreboard. ## Changes - **Types & Schema**: Add vac and game_ban optional boolean fields to MatchPlayer - **Transformer**: Extract vac and game_ban from legacy player.vac and player.game_ban - **UI**: Add "Status" column to details table showing VAC/BAN badges - **Mocks**: Update mock player data with ban status fields ## Implementation Details The backend API provides per-player ban status in match details via the player object (player.vac and player.game_ban). These were previously not being extracted by the transformer. The new Status column displays: - Red "VAC" badge if player has VAC ban - Red "BAN" badge if player has game ban - Both badges if player has both bans - "-" if player has no bans Users can identify banned players at a glance in the scoreboard, improving transparency and match context. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -195,7 +195,10 @@ export function transformPlayerStats(legacy: LegacyPlayerStats): MatchPlayer {
|
|||||||
flash_duration_enemy: legacy.flash?.duration?.enemy,
|
flash_duration_enemy: legacy.flash?.duration?.enemy,
|
||||||
flash_total_self: legacy.flash?.total?.self,
|
flash_total_self: legacy.flash?.total?.self,
|
||||||
flash_total_team: legacy.flash?.total?.team,
|
flash_total_team: legacy.flash?.total?.team,
|
||||||
flash_total_enemy: legacy.flash?.total?.enemy
|
flash_total_enemy: legacy.flash?.total?.enemy,
|
||||||
|
// Ban status
|
||||||
|
vac: legacy.player.vac,
|
||||||
|
game_ban: legacy.player.game_ban
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,11 @@ export const matchPlayerSchema = z.object({
|
|||||||
// Other
|
// Other
|
||||||
crosshair: z.string().optional(),
|
crosshair: z.string().optional(),
|
||||||
color: z.enum(['green', 'yellow', 'purple', 'blue', 'orange', 'grey']).optional(),
|
color: z.enum(['green', 'yellow', 'purple', 'blue', 'orange', 'grey']).optional(),
|
||||||
avg_ping: z.number().nonnegative().optional()
|
avg_ping: z.number().nonnegative().optional(),
|
||||||
|
|
||||||
|
// Ban status
|
||||||
|
vac: z.boolean().optional(),
|
||||||
|
game_ban: z.boolean().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Match schema */
|
/** Match schema */
|
||||||
|
|||||||
@@ -134,6 +134,10 @@ export interface MatchPlayer {
|
|||||||
crosshair?: string;
|
crosshair?: string;
|
||||||
color?: 'green' | 'yellow' | 'purple' | 'blue' | 'orange' | 'grey';
|
color?: 'green' | 'yellow' | 'purple' | 'blue' | 'orange' | 'grey';
|
||||||
avg_ping?: number;
|
avg_ping?: number;
|
||||||
|
|
||||||
|
// Ban status
|
||||||
|
vac?: boolean; // Whether player has VAC ban
|
||||||
|
game_ban?: boolean; // Whether player has game ban
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -74,7 +74,9 @@ export const mockMatchPlayers: MatchPlayer[] = [
|
|||||||
ud_flash: 5,
|
ud_flash: 5,
|
||||||
ud_smoke: 3,
|
ud_smoke: 3,
|
||||||
avg_ping: 25.5,
|
avg_ping: 25.5,
|
||||||
color: 'yellow'
|
color: 'yellow',
|
||||||
|
vac: false,
|
||||||
|
game_ban: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '765611980876543',
|
id: '765611980876543',
|
||||||
@@ -93,7 +95,9 @@ export const mockMatchPlayers: MatchPlayer[] = [
|
|||||||
dmg_enemy: 2180,
|
dmg_enemy: 2180,
|
||||||
dmg_team: 85,
|
dmg_team: 85,
|
||||||
avg_ping: 32.1,
|
avg_ping: 32.1,
|
||||||
color: 'blue'
|
color: 'blue',
|
||||||
|
vac: false,
|
||||||
|
game_ban: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '765611980111111',
|
id: '765611980111111',
|
||||||
@@ -112,7 +116,9 @@ export const mockMatchPlayers: MatchPlayer[] = [
|
|||||||
dmg_enemy: 2680,
|
dmg_enemy: 2680,
|
||||||
dmg_team: 45,
|
dmg_team: 45,
|
||||||
avg_ping: 18.3,
|
avg_ping: 18.3,
|
||||||
color: 'green'
|
color: 'green',
|
||||||
|
vac: false,
|
||||||
|
game_ban: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,28 @@
|
|||||||
if (numValue > 0) return `<span class="badge badge-warning badge-sm">${numValue}</span>`;
|
if (numValue > 0) return `<span class="badge badge-warning badge-sm">${numValue}</span>`;
|
||||||
return '<span class="text-base-content/40">-</span>';
|
return '<span class="text-base-content/40">-</span>';
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'vac' as keyof (typeof playersWithStats)[0],
|
||||||
|
label: 'Status',
|
||||||
|
sortable: true,
|
||||||
|
align: 'center' as const,
|
||||||
|
render: (
|
||||||
|
_value: string | number | boolean | undefined,
|
||||||
|
row: (typeof playersWithStats)[0]
|
||||||
|
) => {
|
||||||
|
const badges = [];
|
||||||
|
if (row.vac) {
|
||||||
|
badges.push('<span class="badge badge-error badge-sm" title="VAC Banned">VAC</span>');
|
||||||
|
}
|
||||||
|
if (row.game_ban) {
|
||||||
|
badges.push('<span class="badge badge-error badge-sm" title="Game Banned">BAN</span>');
|
||||||
|
}
|
||||||
|
if (badges.length > 0) {
|
||||||
|
return `<div class="flex gap-1 justify-center">${badges.join('')}</div>`;
|
||||||
|
}
|
||||||
|
return '<span class="text-base-content/40">-</span>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user