i18n
This commit is contained in:
@@ -27,6 +27,7 @@ import InfiniteScroll from "@/components/infinite-scroll";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useAllPlayerStats } from "../queries";
|
||||
import { PlayerListItemSkeleton } from "./player-stats-table-skeleton";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
|
||||
type SortKey = keyof PlayerStats | "mmr";
|
||||
type SortDirection = "asc" | "desc";
|
||||
@@ -61,6 +62,7 @@ const StatCell = memo(({ label, value }: StatCellProps) => (
|
||||
));
|
||||
|
||||
const PlayerListItem = memo(({ stat, onPlayerClick, mmr, onRegisterViewport, onUnregisterViewport }: PlayerListItemProps) => {
|
||||
const { t } = useLingui();
|
||||
const viewportRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const avg_cups_against = useMemo(() => stat.total_cups_against / stat.matches || 0, [stat.total_cups_against, stat.matches]);
|
||||
@@ -103,11 +105,11 @@ const PlayerListItem = memo(({ stat, onPlayerClick, mmr, onRegisterViewport, onU
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed" ta="right">
|
||||
{stat.matches}
|
||||
<Text span fw={800}>M</Text>
|
||||
<Text span fw={800}><Trans>M</Trans></Text>
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed" ta="right">
|
||||
{stat.tournaments}
|
||||
<Text span fw={800}>T</Text>
|
||||
<Text span fw={800}><Trans>T</Trans></Text>
|
||||
</Text>
|
||||
</Group>
|
||||
|
||||
@@ -125,16 +127,16 @@ const PlayerListItem = memo(({ stat, onPlayerClick, mmr, onRegisterViewport, onU
|
||||
}}
|
||||
>
|
||||
<Group gap='xs' wrap="nowrap">
|
||||
<StatCell label="MMR" value={mmr.toFixed(1)} />
|
||||
<StatCell label="W" value={stat.wins} />
|
||||
<StatCell label="L" value={stat.losses} />
|
||||
<StatCell label="W%" value={`${stat.win_percentage.toFixed(1)}%`} />
|
||||
<StatCell label="AWM" value={stat.margin_of_victory?.toFixed(1) || 0} />
|
||||
<StatCell label="ALM" value={stat.margin_of_loss?.toFixed(1) || 0} />
|
||||
<StatCell label="AC" value={stat.avg_cups_per_match.toFixed(1)} />
|
||||
<StatCell label="ACA" value={avg_cups_against?.toFixed(1) || 0} />
|
||||
<StatCell label="CF" value={stat.total_cups_made} />
|
||||
<StatCell label="CA" value={stat.total_cups_against} />
|
||||
<StatCell label={t`MMR`} value={mmr.toFixed(1)} />
|
||||
<StatCell label={t`W`} value={stat.wins} />
|
||||
<StatCell label={t`L`} value={stat.losses} />
|
||||
<StatCell label={t`W%`} value={`${stat.win_percentage.toFixed(1)}%`} />
|
||||
<StatCell label={t`AWM`} value={stat.margin_of_victory?.toFixed(1) || 0} />
|
||||
<StatCell label={t`ALM`} value={stat.margin_of_loss?.toFixed(1) || 0} />
|
||||
<StatCell label={t`AC`} value={stat.avg_cups_per_match.toFixed(1)} />
|
||||
<StatCell label={t`ACA`} value={avg_cups_against?.toFixed(1) || 0} />
|
||||
<StatCell label={t`CF`} value={stat.total_cups_made} />
|
||||
<StatCell label={t`CA`} value={stat.total_cups_against} />
|
||||
</Group>
|
||||
</ScrollArea>
|
||||
</Stack>
|
||||
@@ -170,6 +172,7 @@ const calculateMMR = (stat: PlayerStats): number => {
|
||||
};
|
||||
|
||||
const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
const { t } = useLingui();
|
||||
const { data: playerStats } = useAllPlayerStats(viewType);
|
||||
const navigate = useNavigate();
|
||||
const [search, setSearch] = useState("");
|
||||
@@ -310,7 +313,7 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
<ChartBarIcon size={32} />
|
||||
</ThemeIcon>
|
||||
<Title order={3} c="dimmed">
|
||||
No Stats Available
|
||||
<Trans>No Stats Available</Trans>
|
||||
</Title>
|
||||
</Stack>
|
||||
);
|
||||
@@ -320,10 +323,10 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
<Container size="100%" px={0}>
|
||||
<Stack gap="xs">
|
||||
<Text px="md" size="10px" lh={0} c="dimmed">
|
||||
Showing {filteredAndSortedStats.length} of {playerStats.length} players
|
||||
<Trans>Showing {filteredAndSortedStats.length} of {playerStats.length} players</Trans>
|
||||
</Text>
|
||||
<TextInput
|
||||
placeholder="Search players"
|
||||
placeholder={t`Search players`}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
leftSection={<MagnifyingGlassIcon size={16} />}
|
||||
@@ -334,13 +337,13 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
<Group px="md" justify="space-between" align="center">
|
||||
<Group gap="xs" w="100%">
|
||||
<div></div>
|
||||
<Text ml='auto' size="xs" c="dimmed">Sort:</Text>
|
||||
<Text ml='auto' size="xs" c="dimmed"><Trans>Sort:</Trans></Text>
|
||||
<UnstyledButton
|
||||
onClick={() => handleSort("mmr")}
|
||||
style={{ display: "flex", alignItems: "center", gap: 4 }}
|
||||
>
|
||||
<Text size="xs" fw={sortConfig.key === "mmr" ? 600 : 400} c={sortConfig.key === "mmr" ? "var(--mantine-color-text)" : "dimmed"}>
|
||||
MMR
|
||||
<Trans>MMR</Trans>
|
||||
</Text>
|
||||
{getSortIcon("mmr")}
|
||||
</UnstyledButton>
|
||||
@@ -350,7 +353,7 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
style={{ display: "flex", alignItems: "center", gap: 4 }}
|
||||
>
|
||||
<Text size="xs" fw={sortConfig.key === "wins" ? 600 : 400} c={sortConfig.key === "wins" ? "var(--mantine-color-text)" : "dimmed"}>
|
||||
Wins
|
||||
<Trans>Wins</Trans>
|
||||
</Text>
|
||||
{getSortIcon("wins")}
|
||||
</UnstyledButton>
|
||||
@@ -360,80 +363,80 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
style={{ display: "flex", alignItems: "center", gap: 4 }}
|
||||
>
|
||||
<Text size="xs" fw={sortConfig.key === "matches" ? 600 : 400} c={sortConfig.key === "matches" ? "var(--mantine-color-text)" : "dimmed"}>
|
||||
Matches
|
||||
<Trans>Matches</Trans>
|
||||
</Text>
|
||||
{getSortIcon("matches")}
|
||||
</UnstyledButton>
|
||||
<Popover position="bottom-end" withArrow shadow="md">
|
||||
<Popover.Target>
|
||||
<ActionIcon variant="subtle" size="sm" aria-label="Stat abbreviations and MMR info">
|
||||
<ActionIcon variant="subtle" size="sm" aria-label={t`Stat abbreviations and MMR info`}>
|
||||
<InfoIcon size={14} />
|
||||
</ActionIcon>
|
||||
</Popover.Target>
|
||||
<Popover.Dropdown>
|
||||
<Box maw={280}>
|
||||
<Text size="sm" fw={500} mb="xs">
|
||||
Stat Abbreviations:
|
||||
<Trans>Stat Abbreviations:</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>M:</strong> Matches
|
||||
<Trans>• <strong>M:</strong> Matches</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>T:</strong> Tournaments
|
||||
<Trans>• <strong>T:</strong> Tournaments</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>MMR:</strong> Matchmaking Rating
|
||||
<Trans>• <strong>MMR:</strong> Matchmaking Rating</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>W:</strong> Wins
|
||||
<Trans>• <strong>W:</strong> Wins</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>L:</strong> Losses
|
||||
<Trans>• <strong>L:</strong> Losses</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>W%:</strong> Win Percentage
|
||||
<Trans>• <strong>W%:</strong> Win Percentage</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>AWM:</strong> Average Win Margin
|
||||
<Trans>• <strong>AWM:</strong> Average Win Margin</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>ALM:</strong> Average Loss Margin
|
||||
<Trans>• <strong>ALM:</strong> Average Loss Margin</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>AC:</strong> Average Cups Per Match
|
||||
<Trans>• <strong>AC:</strong> Average Cups Per Match</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>ACA:</strong> Average Cups Against
|
||||
<Trans>• <strong>ACA:</strong> Average Cups Against</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>CF:</strong> Cups For
|
||||
<Trans>• <strong>CF:</strong> Cups For</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• <strong>CA:</strong> Cups Against
|
||||
<Trans>• <strong>CA:</strong> Cups Against</Trans>
|
||||
</Text>
|
||||
|
||||
<Divider my="sm" />
|
||||
|
||||
<Text size="sm" fw={500} mb="xs">
|
||||
MMR Calculation:
|
||||
<Trans>MMR Calculation:</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• Win Rate (50%)
|
||||
<Trans>• Win Rate (50%)</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• Average Cups/Match (25%)
|
||||
<Trans>• Average Cups/Match (25%)</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• Average Win Margin (15%)
|
||||
<Trans>• Average Win Margin (15%)</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mb={2}>
|
||||
• Match Volume Bonus (10%)
|
||||
<Trans>• Match Volume Bonus (10%)</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mt="xs" c="dimmed">
|
||||
* Confidence penalty applied for players with <15 matches
|
||||
<Trans>* Confidence penalty applied for players with <15 matches</Trans>
|
||||
</Text>
|
||||
<Text size="xs" mt="xs" c="dimmed">
|
||||
** Not an official rating
|
||||
<Trans>** Not an official rating</Trans>
|
||||
</Text>
|
||||
</Box>
|
||||
</Popover.Dropdown>
|
||||
@@ -470,7 +473,7 @@ const PlayerStatsTable = ({ viewType = 'all' }: PlayerStatsTableProps) => {
|
||||
|
||||
{filteredAndSortedStats.length === 0 && search && (
|
||||
<Text ta="center" c="dimmed" py="xl">
|
||||
No players found matching "{search}"
|
||||
<Trans>No players found matching "{search}"</Trans>
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user