Skip to content

Commit

Permalink
Merge pull request #118 from cohstats/refactor-matches
Browse files Browse the repository at this point in the history
Refactor of match page + more tests
  • Loading branch information
petrvecera authored Mar 18, 2023
2 parents 05bf09b + 1406214 commit ca1e57c
Show file tree
Hide file tree
Showing 8 changed files with 334 additions and 125 deletions.
174 changes: 174 additions & 0 deletions __tests__/src/players/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { PlayerReport, ProcessedMatch } from "../../../src/coh3/coh3-types";
import { getPlayerMatchHistoryResult, isPlayerVictorious } from "../../../src/players/utils";

describe("getPlayerMatchHistoryResult", () => {
const matchRecord = {
id: 1,
creator_profile_id: 1,
mapname: "Map1",
maxplayers: 2,
matchtype_id: 1,
description: "Match1",
startgametime: 123456,
completiontime: 123457,
matchhistoryreportresults: [
{
profile_id: 1,
resulttype: 1,
teamid: 1,
race_id: 1,
counters: "",
profile: {
name: "Player1",
alias: "P1",
personal_statgroup_id: 1,
xp: 100,
level: 10,
leaderboardregion_id: 1,
country: "USA",
},
matchhistorymember: {
statgroup_id: 1,
wins: 1,
losses: 0,
streak: 1,
arbitration: 0,
outcome: 1,
oldrating: 1000,
newrating: 1100,
reporttype: 1,
},
},
{
profile_id: 2,
resulttype: 2,
teamid: 2,
race_id: 2,
counters: "",
profile: {
name: "Player2",
alias: "P2",
personal_statgroup_id: 2,
xp: 200,
level: 20,
leaderboardregion_id: 2,
country: "Canada",
},
matchhistorymember: {
statgroup_id: 2,
wins: 0,
losses: 1,
streak: -1,
arbitration: 0,
outcome: 2,
oldrating: 2000,
newrating: 1900,
reporttype: 2,
},
},
],
matchhistoryitems: [],
profile_ids: [1, 2],
};

test("returns the correct result for an existing player", () => {
const result: PlayerReport | null = getPlayerMatchHistoryResult(matchRecord, "2");
expect(result).toEqual(matchRecord.matchhistoryreportresults[1]);
});

test("returns the first result when no player ID is specified", () => {
const result: PlayerReport | null = getPlayerMatchHistoryResult(matchRecord, "");
expect(result).toBeNull();
});

test("returns undefined for a non-existent player", () => {
const result: PlayerReport | null = getPlayerMatchHistoryResult(matchRecord, "3");
expect(result).toBeNull();
});
});

describe("isPlayerVictorious", () => {
const matchRecord: ProcessedMatch = {
id: 1,
creator_profile_id: 1,
mapname: "Map1",
maxplayers: 2,
matchtype_id: 1,
description: "Match1",
startgametime: 123456,
completiontime: 123457,
matchhistoryreportresults: [
{
profile_id: 1,
resulttype: 1,
teamid: 1,
race_id: 1,
counters: "",
profile: {
name: "Player1",
alias: "P1",
personal_statgroup_id: 1,
xp: 100,
level: 10,
leaderboardregion_id: 1,
country: "USA",
},
matchhistorymember: {
statgroup_id: 1,
wins: 1,
losses: 0,
streak: 1,
arbitration: 0,
outcome: 1,
oldrating: 1000,
newrating: 1100,
reporttype: 1,
},
},
{
profile_id: 2,
resulttype: 2,
teamid: 2,
race_id: 2,
counters: "",
profile: {
name: "Player2",
alias: "P2",
personal_statgroup_id: 2,
xp: 200,
level: 20,
leaderboardregion_id: 2,
country: "Canada",
},
matchhistorymember: {
statgroup_id: 2,
wins: 0,
losses: 1,
streak: -1,
arbitration: 0,
outcome: 2,
oldrating: 2000,
newrating: 1900,
reporttype: 2,
},
},
],
matchhistoryitems: [],
profile_ids: [1, 2],
};

test("returns true if the player is victorious", () => {
const result = isPlayerVictorious(matchRecord, "1");
expect(result).toBe(true);
});

test("returns false if the player is not victorious", () => {
const result = isPlayerVictorious(matchRecord, "2");
expect(result).toBe(false);
});

test("returns false if the player ID is not found in the match record", () => {
const result = isPlayerVictorious(matchRecord, "3");
expect(result).toBe(false);
});
});
2 changes: 1 addition & 1 deletion components/internal-timeago.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from "react";

const InternalTimeAgo = ({ timestamp }: { timestamp: number }) => {
return (
<Tooltip label={new Date(timestamp * 1000).toLocaleString()}>
<Tooltip withArrow label={new Date(timestamp * 1000).toLocaleString()}>
<Text>{format(timestamp * 1000, "en")}</Text>
</Tooltip>
);
Expand Down
28 changes: 28 additions & 0 deletions components/matches-table/render-map.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { maps } from "../../src/coh3/coh3-data";
import { Text } from "@mantine/core";
import Image from "next/image";
import React from "react";

const RenderMap = ({ mapName }: { mapName: string }) => {
// In case we don't track the map, eg custom maps
if (!maps[mapName]) {
return (
<div>
<Text align="center" style={{ whiteSpace: "nowrap" }}>
{mapName}
</Text>
</div>
);
}

return (
<div>
<Image src={maps[mapName]?.url} width={60} height={60} alt={mapName} loading="lazy" />
<Text align="center" style={{ whiteSpace: "nowrap" }}>
{maps[mapName]?.name}
</Text>
</div>
);
};

export default RenderMap;
80 changes: 80 additions & 0 deletions components/matches-table/render-players.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Anchor, Group, Text, Tooltip } from "@mantine/core";
import { PlayerReport, raceID } from "../../src/coh3/coh3-types";
import FactionIcon from "../faction-icon";
import { raceIDs } from "../../src/coh3/coh3-data";
import Link from "next/link";
import EllipsisText from "../other/ellipsis-text";
import React from "react";

interface RenderPlayersProps {
playerReports: Array<PlayerReport>;
// ID of the player
profileID: number | string;
}

const RenderPlayers = ({ playerReports, profileID }: RenderPlayersProps) => {
const unrankedWithTooltip = (
<Tooltip
withArrow
multiline
style={{ maxWidth: "30ch" }}
label={"Player is un-ranked in this mode.\n Have less than 10 games."}
>
<Text c={"dimmed"}>N/A</Text>
</Tooltip>
);

return (
<>
{playerReports.map((playerInfo: PlayerReport) => {
const matchHistory = playerInfo.matchhistorymember;
let ratingPlayedWith: string | JSX.Element = `${matchHistory.oldrating}`;
const ratingChange = matchHistory.newrating - matchHistory.oldrating;
const ratingChangeAsElement =
ratingChange > 0 ? (
<Text color={"green"}>+{ratingChange}</Text>
) : ratingChange < 0 ? (
<Text color={"red"}>{ratingChange}</Text>
) : (
<Text>{ratingChange}</Text>
);

ratingPlayedWith =
matchHistory.losses + matchHistory.wins >= 10 ? ratingPlayedWith : unrankedWithTooltip;

const ratingElement = (
<>
<span style={{ width: "4ch", textAlign: "left" }}>{ratingPlayedWith}</span>
<span>{ratingChangeAsElement}</span>
</>
);

return (
<div key={playerInfo.profile_id}>
<Group spacing={"xs"}>
<FactionIcon name={raceIDs[playerInfo.race_id as raceID]} width={20} />
<> {ratingElement}</>
<Anchor
key={playerInfo.profile_id}
component={Link}
href={`/players/${playerInfo.profile_id}`}
>
{`${playerInfo.profile_id}` === `${profileID}` ? (
<Text fw={700}>
<EllipsisText text={playerInfo.profile["alias"]} />
</Text>
) : (
<Text>
<EllipsisText text={playerInfo.profile["alias"]} />
</Text>
)}
</Anchor>
</Group>
</div>
);
})}
</>
);
};

export default RenderPlayers;
12 changes: 12 additions & 0 deletions components/other/dynamic-timeago.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import dynamic from "next/dynamic";

/**
* Because of SSR rendering issues, we need to use dynamic imports for this component
*/
const DynamicTimeAgo = dynamic(() => import("../internal-timeago"), {
ssr: false,
// @ts-ignore
loading: () => "Calculating...",
});

export default DynamicTimeAgo;
Loading

0 comments on commit ca1e57c

Please sign in to comment.