From a7e05319be355eec28a698fdbf04a98c74b9330d Mon Sep 17 00:00:00 2001 From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com> Date: Sat, 30 Jan 2021 16:24:26 +0200 Subject: [PATCH] build page stats --- components/builds/APStats.tsx | 100 ++++++++++++++++++++++++++++++++++ hooks/builds.ts | 44 +++++++++++++++ pages/builds/[[...slug]].tsx | 44 ++++++++++++--- 3 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 components/builds/APStats.tsx diff --git a/components/builds/APStats.tsx b/components/builds/APStats.tsx new file mode 100644 index 000000000..e6434a124 --- /dev/null +++ b/components/builds/APStats.tsx @@ -0,0 +1,100 @@ +import { Flex } from "@chakra-ui/react"; +import { Trans } from "@lingui/macro"; +import AbilityIcon from "components/common/AbilityIcon"; +import SubText from "components/common/SubText"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "components/common/Table"; +import { mainOnlyAbilities } from "lib/lists/abilities"; + +interface Props { + stats: { + code: string; + average: number; + counts: number[][]; + }[]; +} + +const APStats: React.FC = ({ stats }) => { + if (Number.isNaN(stats[0].average)) return null; + return ( + + + + + + Ability + + + Average AP + + + Popular values + + + + + {stats + .filter((stat) => !mainOnlyAbilities.includes(stat.code as any)) + .map((stat) => { + return ( + + + + + + {stat.average.toFixed(2)} + + + {stat.counts.map((count) => { + return ( + + {count[0]} {count[1]} + + ); + })} + + + ); + })} + +
+ + + + + + Ability + + + Appearance % + + + + + {stats + .filter((stat) => mainOnlyAbilities.includes(stat.code as any)) + .map((stat) => { + return ( + + + + + + {(stat.average * 10).toFixed(2)}% + + + ); + })} + +
+
+ ); +}; + +export default APStats; diff --git a/hooks/builds.ts b/hooks/builds.ts index 2daf92165..871778d04 100644 --- a/hooks/builds.ts +++ b/hooks/builds.ts @@ -205,11 +205,55 @@ export function useBuildsByWeapon() { [] ); + const stats = Object.entries( + buildsToShow.reduce( + (acc: Record>, buildArr) => { + buildArr.forEach(({ abilityPoints }) => { + abilities.forEach(({ code }) => { + // @ts-ignore + const buildAPCount = (abilityPoints[code] as number) ?? 0; + let existingApRecord = acc[code][buildAPCount] ?? 0; + acc[code][buildAPCount] = ++existingApRecord; + }); + }); + + return acc; + }, + getStatsInitialValue() + ) + ) + .map(([abilityCode, apCounts]) => { + return { + code: abilityCode, + average: + Object.entries(apCounts).reduce( + (acc, cur) => Number(cur[0]) * cur[1] + acc, + 0 + ) / Object.values(apCounts).reduce((acc, cur) => acc + cur, 0), + counts: Object.entries(apCounts) + .map(([ap, count]) => [Number(ap), count]) + .sort((a, b) => b[1] - a[1]) + .slice(0, 3), + }; + }) + .sort((a, b) => b.average - a.average); + return { data: buildsToShow, isLoading: state.weapon && !data, + stats, state, dispatch, hiddenBuildCount: buildArrays.length - buildsToShow.length, }; } + +function getStatsInitialValue() { + const result: Partial>> = {}; + + abilities.forEach(({ code }) => { + result[code] = {}; + }); + + return result as Record>; +} diff --git a/pages/builds/[[...slug]].tsx b/pages/builds/[[...slug]].tsx index 7a0517a0e..2a553bac3 100644 --- a/pages/builds/[[...slug]].tsx +++ b/pages/builds/[[...slug]].tsx @@ -1,5 +1,6 @@ import { Box, Button, Flex } from "@chakra-ui/react"; import { t, Trans } from "@lingui/macro"; +import APStats from "components/builds/APStats"; import BuildCard from "components/builds/BuildCard"; import BuildFilters from "components/builds/BuildFilters"; import BuildsSkeleton from "components/builds/BuildsSkeleton"; @@ -10,11 +11,13 @@ import WeaponImage from "components/common/WeaponImage"; import WeaponSelector from "components/common/WeaponSelector"; import { useBuildsByWeapon } from "hooks/builds"; import { useMyTheme, useUser } from "hooks/common"; -import { RiTShirtLine } from "react-icons/ri"; +import { useState } from "react"; +import { RiBarChart2Fill, RiTShirtLine } from "react-icons/ri"; const BuildsPage = () => { const { data, + stats, isLoading, state, dispatch, @@ -22,6 +25,8 @@ const BuildsPage = () => { } = useBuildsByWeapon(); const [user] = useUser(); const { secondaryBgColor, themeColorShade } = useMyTheme(); + const [showStats, setShowStats] = useState(true); + return ( <> @@ -36,20 +41,39 @@ const BuildsPage = () => { {state.weapon && ( <> - {user && ( - - - - )} + + + {user && ( + + + + )} + { )} + {showStats && } + {isLoading && }