Skip to content

Commit

Permalink
Add total games stats and error handling (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
petrvecera authored Jun 6, 2022
1 parent fb6f6ac commit 04f3f28
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 84 deletions.
109 changes: 56 additions & 53 deletions packages/web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Leaderboards from "./pages/ladders";
import PlayerCard from "./pages/players";
import MapStats from "./pages/map-stats";
import LiveMatches from "./pages/live-matches";
import { ErrorBoundary } from "./components/error-boundary";

const { Content } = Layout;

Expand All @@ -43,59 +44,61 @@ const App: React.FC = () => {
<Layout className="layout">
<MainHeader />
<Content>
<Switch>
<Route path={"/"} exact={true}>
<MainHome />
</Route>
<Route path={routes.fullStatsOldDetails()}>
<OldStats />
</Route>
<Route path={routes.mapStats()}>
<MapStats />
</Route>
<Route path={routes.statsBase()}>
<CustomStats />
</Route>
<Route path={routes.playerCardWithIdAndName()}>
<PlayerCard />
</Route>
<Route path={routes.playerCardWithId()}>
<PlayerCard />
</Route>
<Route path={routes.playerCardBase()}>
<CustomSearch />
</Route>
<Route path={routes.leaderboardsBase()}>
<Leaderboards />
</Route>
<Route path={routes.commanderByID()}>
<CommanderDetails />
</Route>
<Route path={routes.commanderList()}>
<CommandersList />
</Route>
<Route path={routes.commanderBase()}>
<RacePicker />
</Route>
<Route path={routes.desktopAppBase()}>
<DesktopApp />
</Route>
<Route path={routes.liveMatchesBase()}>
<LiveMatches />
</Route>
<Route path={routes.aboutBase()}>
<About />
</Route>
<Route path={routes.bulletinsBase()}>
<BulletinList />
</Route>
<Route path={routes.searchWithParam()}>
<CustomSearch />
</Route>
<Route path={routes.searchBase()}>
<CustomSearch />
</Route>
</Switch>
<ErrorBoundary>
<Switch>
<Route path={"/"} exact={true}>
<MainHome />
</Route>
<Route path={routes.fullStatsOldDetails()}>
<OldStats />
</Route>
<Route path={routes.mapStats()}>
<MapStats />
</Route>
<Route path={routes.statsBase()}>
<CustomStats />
</Route>
<Route path={routes.playerCardWithIdAndName()}>
<PlayerCard />
</Route>
<Route path={routes.playerCardWithId()}>
<PlayerCard />
</Route>
<Route path={routes.playerCardBase()}>
<CustomSearch />
</Route>
<Route path={routes.leaderboardsBase()}>
<Leaderboards />
</Route>
<Route path={routes.commanderByID()}>
<CommanderDetails />
</Route>
<Route path={routes.commanderList()}>
<CommandersList />
</Route>
<Route path={routes.commanderBase()}>
<RacePicker />
</Route>
<Route path={routes.desktopAppBase()}>
<DesktopApp />
</Route>
<Route path={routes.liveMatchesBase()}>
<LiveMatches />
</Route>
<Route path={routes.aboutBase()}>
<About />
</Route>
<Route path={routes.bulletinsBase()}>
<BulletinList />
</Route>
<Route path={routes.searchWithParam()}>
<CustomSearch />
</Route>
<Route path={routes.searchBase()}>
<CustomSearch />
</Route>
</Switch>
</ErrorBoundary>
</Content>
<MainFooter />
</Layout>
Expand Down
1 change: 1 addition & 0 deletions packages/web/src/coh/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ type TypeAnalysisObject = {
usf: Record<string, number>;
};
factionMatrix: Record<string, { wins: number; losses: number }>;
totalGames?: number;
};

interface StatsDataObject {
Expand Down
66 changes: 66 additions & 0 deletions packages/web/src/components/error-boundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from "react";
import { AlertBox } from "./alert-box";
import { Row, Typography } from "antd";
import config from "../config";
const { Text } = Typography;

class ErrorBoundary extends React.Component {
constructor(props: any) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error: any) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

componentDidCatch(error: any, errorInfo: any) {
// You can also log the error to an error reporting service
// logErrorToMyService(error, errorInfo);
}

render() {
// @ts-ignore
if (this.state.hasError) {
// You can render any custom fallback UI
return (
<Row justify="center" style={{ paddingTop: "10px" }}>
<AlertBox
type={"error"}
message={"There was an error rendering the component."}
description={
<div>
Please refresh the app (press F5). If the problem persists after refreshing the
page please report it together with <Text strong>screenshot, url</Text> and
preferably copy all the error text which is in the Console of browser developer
tools (
<a
href={"https://updraftplus.com/faqs/how-do-i-open-my-browsers-developer-tools/"}
target="_blank"
rel="noopener noreferrer"
>
{" "}
how to open dev tools
</a>
) in our Discord{" "}
<a href={config.discordInviteLink} target="_blank" rel="noopener noreferrer">
<img
width={30}
height={30}
src={"/resources/discord-icon.svg"}
alt={"Discord Logo"}
/>
</a>
</div>
}
/>
</Row>
);
}

return this.props.children;
}
}

export { ErrorBoundary };
3 changes: 2 additions & 1 deletion packages/web/src/components/main-footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import { Footer } from "antd/lib/layout/layout";
import { Divider } from "antd";
import { Link } from "react-router-dom";
import config from "../config";

export const MainFooter: React.FC = () => {
return (
Expand All @@ -19,7 +20,7 @@ export const MainFooter: React.FC = () => {
<a href={"https://github.com/cohstats/coh2stats"} target="_blank" rel="noopener noreferrer">
<img width={30} height={30} src={"/resources/github-dark.png"} alt={"GitHub Logo"} />
</a>{" "}
<a href={"https://discord.gg/jRrnwqMfkr"} target="_blank" rel="noopener noreferrer">
<a href={config.discordInviteLink} target="_blank" rel="noopener noreferrer">
<img width={30} height={30} src={"/resources/discord-icon.svg"} alt={"Discord Logo"} />
</a>
<br />
Expand Down
3 changes: 3 additions & 0 deletions packages/web/src/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const firebaseFunctions = {
location: "us-east4",
};

const discordInviteLink = "https://discord.gg/jRrnwqMfkr";

const devHostnames = ["localhost", "coh2-ladders-dev.web.app"];

const rrfConfig: Partial<ReactReduxFirebaseConfig> = {
Expand All @@ -32,6 +34,7 @@ const config = {
rrfConfig,
firebaseFunctions,
devHostnames,
discordInviteLink,
};

// The date when we exported the data for the bulletins and commanders
Expand Down
19 changes: 13 additions & 6 deletions packages/web/src/pages/about/about.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,19 @@ const About: React.FC = () => {
</Link>
<br />
<br />
However based on{" "}
<Link href="http://coh2chart.com/" target="_blank">
this data
</Link>{" "}
from 2017 we expect that there is around ~50k matches/day. Which means{" "}
<Text strong>we are processing around 8% of all games</Text>.
<s>
However based on{" "}
<Link href="http://coh2chart.com/" target="_blank">
this data
</Link>{" "}
from 2017 we expect that there is around ~50k matches/day. Which means{" "}
<Text strong>we are processing around 8% of all games</Text>.
</s>
<br />
Update June 2022: Thanks to the access to the live games we know that we track 40% of all
games.
<br />
To be precise: 1v1 - 25%, 2v2 - 37%, 3v3 - 41%, 4v4 - 47%. We aim to get to 100%
<br />
<br />
The amount of data with some types of games is really a problem. You can see that winrate
Expand Down
24 changes: 19 additions & 5 deletions packages/web/src/pages/map-stats/map-stats-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const MapStatsDetails: React.FC<IProps> = ({ urlChanger, specificData }) => {
const frequency = query.get("range") || "";
let map = query.get("map") || "8p_redball_express";

// const totalGames = specificData.totalGames || null;
const totalGames = specificData.totalGames || null;
// We added total games to the object with the maps / we need to remove it
// We need to do a copy of the object because we can't remove the key otherwise
const data: Record<string, any> = JSON.parse(JSON.stringify(specificData));
Expand Down Expand Up @@ -117,6 +117,22 @@ const MapStatsDetails: React.FC<IProps> = ({ urlChanger, specificData }) => {
);
};

let gamesAnalyzed = <>Games analyzed {amountOfGames}</>;

if (totalGames && totalGames > amountOfGames) {
gamesAnalyzed = (
<>
Games analyzed {amountOfGames}/{totalGames} -{" "}
{Math.round((amountOfGames / totalGames) * 100)}%{" "}
<Helper
text={
"From June 2022 we are aware of 90% of total played automatch games. It's possible that some games which are under 10 minutes in duration are not counted."
}
/>
</>
);
}

const cardWidth = 510;
const cardHeight = 420;

Expand All @@ -127,9 +143,7 @@ const MapStatsDetails: React.FC<IProps> = ({ urlChanger, specificData }) => {
</Row>
<Row justify={"center"}>
<div style={{ textAlign: "center" }}>
<span style={{ fontSize: 20, fontWeight: 600 }}>
Amount of games for this analysis {amountOfGames}
</span>
<span style={{ fontSize: 20, fontWeight: 600 }}>{gamesAnalyzed}</span>
<br />
<span>
{
Expand Down Expand Up @@ -179,7 +193,7 @@ const MapStatsDetails: React.FC<IProps> = ({ urlChanger, specificData }) => {
<MapsWinRateChart data={data} />
</Card>
<Card
title={`Games Played ${type}`}
title={`Games Analyzed ${type}`}
bodyStyle={
isMobile
? { width: "90vw", height: 300 }
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/pages/stats/custom-stats-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const CustomStatsDetails: React.FC<IProps> = ({ urlChanger, specificData }) => {
<>
<Row justify={"center"} style={{ paddingTop: 10 }}>
<Space size={"large"} wrap style={{ display: "flex", justifyContent: "center" }}>
<RegularStatsCards title={`Games Played ${type}`}>
<RegularStatsCards title={`Games Analyzed ${type}`}>
<WinsChart data={data} />
</RegularStatsCards>
<RegularStatsCards title={`Faction winrate ${type}`}>
Expand Down
69 changes: 69 additions & 0 deletions packages/web/src/pages/stats/general-charts/total-games-pie.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { ResponsivePie } from "@nivo/pie";
import React from "react";
import { Empty } from "antd";

import { StatsDataObject, statsTypesInDB } from "../../../coh/types";

interface FactionsPlayedPieChartProps {
data: StatsDataObject;
}

export const TotalGamesPieChart: React.FC<FactionsPlayedPieChartProps> = ({ data }) => {
const chartData = [];

// "1v1", "2v2", "3v3" ...
for (let type of statsTypesInDB) {
chartData.push({
id: type,
label: type,
value: data[type as "1v1" | "2v2" | "3v3" | "4v4"].totalGames,
});
}

if (!data["1v1"].totalGames && !((data["1v1"].totalGames || 0) > data["1v1"].matchCount)) {
return <Empty description={"We started tracking total games from June 2022"} />;
}

return (
<ResponsivePie
// @ts-ignore
data={chartData}
margin={{ bottom: 5, top: 5, right: 10 }}
innerRadius={0.4}
padAngle={0.7}
cornerRadius={3}
activeOuterRadiusOffset={8}
borderWidth={1}
arcLinkLabelsSkipAngle={10}
arcLinkLabelsTextColor="#333333"
arcLinkLabelsThickness={2}
arcLabelsSkipAngle={10}
enableArcLinkLabels={false}
legends={[
{
anchor: "bottom-right",
direction: "column",
justify: false,
translateX: 45,
translateY: 0,
itemsSpacing: 5,
itemWidth: 100,
itemHeight: 18,
itemTextColor: "#999",
itemDirection: "left-to-right",
itemOpacity: 1,
symbolSize: 18,
symbolShape: "circle",
effects: [
{
on: "hover",
style: {
itemTextColor: "#000",
},
},
],
},
]}
/>
);
};
Loading

0 comments on commit 04f3f28

Please sign in to comment.