Skip to content

Commit 8678b73

Browse files
committed
Add recent month top players block
1 parent 73683e5 commit 8678b73

5 files changed

Lines changed: 38 additions & 8 deletions

File tree

apps/api/src/app/getters/getTopStats.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ export const getTopStats = async () => {
2525
ORDER BY titles DESC
2626
LIMIT 10;
2727
`,
28-
prisma.$queryRaw<Array<{ playerId: string; winrate: number }>>`
28+
prisma.$queryRaw<Array<{ playerId: string; winrate: number; games: number }>>`
2929
SELECT "playerId"
30+
, CAST(COUNT("playerId") AS INTEGER) AS games
3031
, 1.0 * SUM(CASE WHEN "isWin" THEN 1 ELSE 0 END) / COUNT("playerId") AS winrate
3132
FROM "Game"
3233
GROUP BY "playerId"
@@ -87,8 +88,9 @@ export const getTopStats = async () => {
8788
})
8889

8990
return {
90-
byWinrate: winrates.map(({ playerId, winrate }) => ({
91+
byWinrate: winrates.map(({ playerId, winrate, games }) => ({
9192
winrate,
93+
games,
9294
name: players.find((x) => x.id === playerId)?.name,
9395
})),
9496
byWins: winners.map(({ playerId, _count }) => ({

apps/api/src/app/routes/top/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ const getTopTitles = async (since?: Date) => {
5555
}
5656

5757
const getTopWinrates = async (minGamesThresholdForWinrate: number, since?: Date) => {
58-
return prisma.$queryRaw<Array<{ playerId: string; winrate: number }>>`
58+
return prisma.$queryRaw<Array<{ playerId: string; winrate: number; games: number }>>`
5959
SELECT "playerId",
60+
CAST(COUNT("playerId") AS INTEGER) AS games,
6061
1.0 * SUM(CASE WHEN "isWin" THEN 1 ELSE 0 END) / COUNT("playerId") AS winrate
6162
FROM "Game"
6263
${since ? Prisma.sql`WHERE "endAt" >= ${since}` : Prisma.sql``}
@@ -106,8 +107,9 @@ const getTopStats = async ({
106107
return {
107108
gamesTotal,
108109
winsTotal,
109-
byWinrate: winrates.map(({ playerId, winrate }) => ({
110+
byWinrate: winrates.map(({ playerId, winrate, games }) => ({
110111
winrate,
112+
games,
111113
name: players.find((x) => x.id === playerId)?.name,
112114
})),
113115
byWins: winners.map(({ playerId, _count }) => ({

apps/web/src/app/page.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ async function getData() {
4141
`/top?minGamesThresholdForWinrate=27&since=${encodeURIComponent(dayjs().subtract(1, 'year').toISOString())}`,
4242
{ next: { revalidate: 300 }, cache: 'force-cache' },
4343
).then((r) => r.json())
44+
const topVeryRecentRes: { data: TopPlayers } = await fetchApi(
45+
`/top?minGamesThresholdForWinrate=15&since=${encodeURIComponent(dayjs().subtract(1, 'month').toISOString())}`,
46+
{ next: { revalidate: 300 }, cache: 'force-cache' },
47+
).then((r) => r.json())
4448
const res = await fetchApi('/main', { next: { revalidate: 300 }, cache: 'force-cache' })
4549
const response: {
4650
data: {
@@ -68,6 +72,7 @@ async function getData() {
6872
topPlayers: topRes.data,
6973
topPlayersWithManyGames: topWithManyGamesRes.data,
7074
topPlayersRecent: topRecentRes.data,
75+
topPlayersVeryRecent: topVeryRecentRes.data,
7176
nickname: sample(nicknames) ?? '',
7277
}
7378
}
@@ -89,6 +94,6 @@ type TopPlayers = {
8994
winsTotal: number
9095
minGamesThresholdForWinrate: number
9196
byWins: Array<Pick<Player, 'name'> & { wins: number }>
92-
byWinrate: Array<Pick<Player, 'name'> & { winrate: number }>
97+
byWinrate: Array<Pick<Player, 'name'> & { winrate: number; games: number }>
9398
byTitles: Array<Pick<Player, 'name'> & { titles: number }>
9499
}

apps/web/src/screens/main/List.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const List = ({
1515
items: Array<{
1616
name: string
1717
count?: string
18+
secondaryCount?: string
1819
}>
1920
onLinkClick: (name: string) => void
2021
placeholder?: ReactNode
@@ -42,7 +43,16 @@ export const List = ({
4243
}}
4344
>
4445
<span className="overflow-hidden text-ellipsis whitespace-nowrap">{item.name}</span>
45-
{item.count && <span className="tabular-nums">{item.count}</span>}
46+
{item.count && (
47+
<span className="ml-auto tabular-nums">
48+
{item.secondaryCount && (
49+
<span className="mr-1 text-xs text-gray-400 dark:text-gray-500">
50+
{item.secondaryCount}
51+
</span>
52+
)}
53+
{item.count}
54+
</span>
55+
)}
4656
</Link>
4757
))}
4858
</div>

apps/web/src/screens/main/Stats.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const Stats = memo(
3535
combosData,
3636
topPlayers,
3737
topPlayersRecent,
38+
topPlayersVeryRecent,
3839
topPlayersWithManyGames,
3940
onLinkClick,
4041
}: Props & { onLinkClick: (name: string) => void }) => {
@@ -64,16 +65,25 @@ export const Stats = memo(
6465
<div className="flex justify-between gap-1">
6566
<h3 className="text-xl font-semibold">
6667
Top Players{' '}
67-
<span className="font-normal text-gray-600 dark:text-gray-400">(Last year)</span>
68+
<span className="font-normal text-gray-600 dark:text-gray-400">(Last month)</span>
6869
</h3>
6970
</div>
7071
<TopList
7172
showFavorites
72-
top={topPlayersRecent}
7373
favorites={favorites}
74+
top={topPlayersVeryRecent}
7475
onLinkClick={onLinkClick}
7576
/>
7677
</div>
78+
<div className="space-y-1">
79+
<div className="flex justify-between gap-1">
80+
<h3 className="text-xl font-semibold">
81+
Top Players{' '}
82+
<span className="font-normal text-gray-600 dark:text-gray-400">(Last year)</span>
83+
</h3>
84+
</div>
85+
<TopList top={topPlayersRecent} onLinkClick={onLinkClick} />
86+
</div>
7787
<div className="space-y-1">
7888
<div className="flex justify-between gap-1">
7989
<h3 className="text-xl font-semibold">
@@ -248,6 +258,7 @@ const TopList = ({
248258
}
249259
items={top.byWinrate.map((item) => ({
250260
name: item.name,
261+
secondaryCount: `${item.games}g`,
251262
count: formatNumber(item.winrate * 100, {
252263
maximumFractionDigits: 2,
253264
minimumFractionDigits: 2,

0 commit comments

Comments
 (0)