Skip to content

Commit

Permalink
refactor: /stats page (#571)
Browse files Browse the repository at this point in the history
* refactor: /stats page

* refactor: utils.ts

react-hooks/rules-of-hooks
  • Loading branch information
jy95 authored Sep 8, 2024
1 parent cfc1f38 commit 5a5bc5a
Show file tree
Hide file tree
Showing 7 changed files with 486 additions and 367 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"i18n-ally.localesPaths": [
"messages"
]
],
"i18n-ally.keystyle": "nested"
}
169 changes: 169 additions & 0 deletions src/app/[locale]/stats/_client/GeneralStats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
"use client";

// hooks
import { Suspense } from "react";
import { useTranslations } from "next-intl";

// MUI component
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
import ListItemAvatar from "@mui/material/ListItemAvatar";
import Avatar from "@mui/material/Avatar";

// Icons
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
import HourglassFullIcon from "@mui/icons-material/HourglassFull";
import HourglassBottomIcon from "@mui/icons-material/HourglassBottom";
import HourglassTopIcon from "@mui/icons-material/HourglassTop";
import YouTubeIcon from "@mui/icons-material/YouTube";

// Utils
import { useCalcDate, usePrettyDuration } from "./utils";

// Types
import type { statsProperty } from "@/app/api/stats/route";

type Props = {
stats: statsProperty
}

export default function GeneralStats ({stats}: Props) {

const t = useTranslations();
const generalStats = stats.general;

// hooks calls
const total_duration = usePrettyDuration(generalStats.total_time);
const total_duration_available = usePrettyDuration(generalStats.total_time_available);
const total_duration_unavailable = usePrettyDuration(generalStats.total_time_unavailable);
const how_long_since_channel_start = useCalcDate(generalStats.channel_start_date).result;

return (
<Grid item xs={12} md={12} lg={12}>
<Paper
sx={{
p: 2,
display: "flex",
flexDirection: "column",
}}
>
<Typography component="h2" variant="h6" color="primary" gutterBottom>
{t("stats.generalStats.title")}
</Typography>
<List>
<Accordion key={"total_games"}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls={"panel-content_total_games"}
id={"panel-header_total_games"}
>
<ListItemAvatar>
<Avatar>
<SportsEsportsIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={t("stats.generalStats.total_games")}
secondary={generalStats.total}
/>
</AccordionSummary>
<Suspense fallback={null}>
<List>
<ListItem>
<ListItemAvatar>
<Avatar>
<SportsEsportsIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={t("stats.generalStats.total_games_available")}
secondary={generalStats.total_available}
/>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar>
<SportsEsportsIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={t("stats.generalStats.total_games_unavailable")}
secondary={generalStats.total_unavailable}
/>
</ListItem>
</List>
</Suspense>
</Accordion>

<Accordion key={"total_duration"}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls={"panel-content_total_duration"}
id={"panel-header_total_duration"}
>
<ListItemAvatar>
<Avatar>
<HourglassFullIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={t("stats.generalStats.total_duration")}
secondary={total_duration}
/>
</AccordionSummary>
<Suspense fallback={null}>
<List>
<ListItem>
<ListItemAvatar>
<Avatar>
<HourglassBottomIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={t("stats.generalStats.total_duration_available")}
secondary={total_duration_available}
/>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar>
<HourglassTopIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={t("stats.generalStats.total_duration_unavailable")}
secondary={total_duration_unavailable}
/>
</ListItem>
</List>
</Suspense>
</Accordion>

<ListItem>
<ListItemAvatar>
<Avatar>
<YouTubeIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={t("stats.generalStats.channel_start_date")}
secondary={`${new Date(
generalStats.channel_start_date,
).toLocaleDateString()} ${t(
"stats.generalStats.channel_start_date_details",
{ value: how_long_since_channel_start },
)}`}
/>
</ListItem>
</List>
</Paper>
</Grid>
);
};
92 changes: 92 additions & 0 deletions src/app/[locale]/stats/_client/GenresChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"use client";

// hooks
import { useTranslations } from "next-intl";
import { useAppSelector } from "@/redux/hooks";

// MUI component
import Typography from "@mui/material/Typography";
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";

// Recharts components
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from "recharts";

// Types
import type { statsProperty } from "@/app/api/stats/route";

type Props = {
stats: statsProperty
}

export default function GenresChart({stats}: Props) {

const t = useTranslations();
const currentColor = useAppSelector((state) => state.themeColor.currentColor);

const strokeColor = currentColor === "dark" ? "white" : "dark";
// for genre chart
const genresData = stats.genres.map(genre => ({
key: genre.id,
category: t(`gamesLibrary.gamesGenres.${genre.id}` as any),
...genre
}));

if (genresData.length === 0) {
return <></>;
}

return (
<Grid item xs={12} md={8} lg={8}>
<Paper
sx={{
p: 2,
display: "flex",
flexDirection: "column",
height: 360,
}}
>
<Typography
component="h2"
variant="h6"
color="primary"
gutterBottom
>
{t("stats.genresChart.title")}
</Typography>
<ResponsiveContainer>
<BarChart data={genresData}>
<CartesianGrid strokeDasharray="2 2" />
<XAxis dataKey="category" stroke={strokeColor} />
<YAxis stroke={strokeColor} />
<Tooltip contentStyle={{ backgroundColor: currentColor }} />
<Bar
type="monotone"
dataKey="total_available"
stackId="1"
stroke="#82ca9d"
fill="#82ca9d"
name={t("stats.genresChart.total_available")}
/>
<Bar
type="monotone"
dataKey="total_unavailable"
stackId="1"
stroke="#8884d8"
fill="#8884d8"
name={t("stats.genresChart.total_unavailable")}
/>
</BarChart>
</ResponsiveContainer>
</Paper>
</Grid>
);
}
87 changes: 87 additions & 0 deletions src/app/[locale]/stats/_client/PlatformsChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"use client";

// hooks
import { useTranslations } from "next-intl";
import { useAppSelector } from "@/redux/hooks";

// MUI component
import Typography from "@mui/material/Typography";
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";

// Recharts components
import {
PolarAngleAxis,
PolarGrid,
Radar,
RadarChart,
ResponsiveContainer,
Legend,
} from "recharts";

// Types
import type { statsProperty } from "@/app/api/stats/route";

type Props = {
stats: statsProperty
}

export default function PlatformsChart({stats} : Props) {

const t = useTranslations();
const currentColor = useAppSelector((state) => state.themeColor.currentColor);

const strokeColor = currentColor === "dark" ? "white" : "dark";
const platformsData = stats.platforms
.map(platform => ({
key: platform.platform,
...platform
}));

if (platformsData.length === 0) {
return <></>;
}

return (
<Grid item xs={12} md={4} lg={4}>
<Paper
sx={{
p: 2,
display: "flex",
flexDirection: "column",
height: 360,
}}
>
<Typography
component="h2"
variant="h6"
color="primary"
gutterBottom
>
{t("stats.platformsChart.title")}
</Typography>
<ResponsiveContainer>
<RadarChart outerRadius={90} data={platformsData}>
<PolarGrid />
<PolarAngleAxis dataKey="key" stroke={strokeColor} />
<Radar
name={t("stats.platformsChart.total_available")}
dataKey="total_available"
stroke="#1fa134"
fill="#1fa134"
fillOpacity={0.6}
/>
<Radar
name={t("stats.platformsChart.total_unavailable")}
dataKey="total_unavailable"
stroke="#8884d8"
fill="#8884d8"
fillOpacity={0.6}
/>
<Legend />
</RadarChart>
</ResponsiveContainer>
</Paper>
</Grid>
);
}
Loading

0 comments on commit 5a5bc5a

Please sign in to comment.