Skip to content

Commit eb80e47

Browse files
authored
Merge pull request #467 from TaloDev/develop
Release 0.69.0
2 parents ab24c72 + c3ac7ff commit eb80e47

36 files changed

+924
-69
lines changed

CLAUDE.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ Located in [src/utils/](src/utils/):
131131
- `useNodeGraph` - Graph visualization for save data (using @xyflow/react)
132132
- `buildError` - Normalize error objects
133133
- `canPerformAction` / `canViewPage` - Permission checking
134-
- `getEventColour` - Consistent color assignment for events
135134

136135
## Important Patterns
137136

package-lock.json

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@tippyjs/react": "^4.2.5",
1919
"@xyflow/react": "^12.2.1",
2020
"axios": "^1.13.5",
21+
"chroma-js": "^3.2.0",
2122
"clsx": "^2.0.0",
2223
"dagre": "^0.8.5",
2324
"date-fns": "^2.29.3",
@@ -47,6 +48,7 @@
4748
"@testing-library/jest-dom": "^6.4.2",
4849
"@testing-library/react": "^15.0.4",
4950
"@testing-library/user-event": "^14.5.2",
51+
"@types/chroma-js": "^3.1.2",
5052
"@types/dagre": "^0.7.52",
5153
"@types/lodash-es": "^4.17.12",
5254
"@types/randomcolor": "^0.5.9",
@@ -79,7 +81,7 @@
7981
"lint-staged": {
8082
"*.{ts,js,tsx,jsx}": "eslint --fix"
8183
},
82-
"version": "0.68.0",
84+
"version": "0.69.0",
8385
"engines": {
8486
"node": "24.x"
8587
},

src/Router.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const PlayerProfile = lazy(() => import(/* webpackChunkName: 'player-profile' */
3939
const PlayerLeaderboardEntries = lazy(() => import(/* webpackChunkName: 'player-leaderboard-entries' */ './pages/PlayerLeaderboardEntries'))
4040
const ForgotPassword = lazy(() => import(/* webpackChunkName: 'forgot-password' */ './pages/ForgotPassword'))
4141
const ResetPassword = lazy(() => import(/* webpackChunkName: 'reset-password' */ './pages/ResetPassword'))
42+
const PlayerAuthActivities = lazy(() => import(/* webpackChunkName: 'player-auth-activities' */ './pages/PlayerAuthActivities'))
4243
const PlayerSaves = lazy(() => import(/* webpackChunkName: 'player-saves' */ './pages/PlayerSaves'))
4344
const PlayerSaveContent = lazy(() => import(/* webpackChunkName: 'player-save-content' */ './pages/PlayerSaveContent'))
4445
const NotFound = lazy(() => import(/* webpackChunkName: 'not-found' */ './pages/NotFound'))
@@ -112,6 +113,7 @@ function Router({
112113
<Route path={routes.playerProfile} element={<PlayerProfile />} />
113114
<Route path={routes.playerLeaderboardEntries} element={<PlayerLeaderboardEntries />} />
114115
<Route path={routes.playerSaveContent} element={<PlayerSaveContent />} />
116+
<Route path={routes.playerAuthActivities} element={<PlayerAuthActivities />} />
115117
<Route path={routes.playerSaves} element={<PlayerSaves />} />
116118
<Route path={routes.feedback} element={<Feedback />} />
117119
{canViewPage(user, routes.feedbackCategories) && <Route path={routes.feedbackCategories} element={<FeedbackCategories />} />}

src/api/useGameActivities.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,32 @@ import makeValidatedGetRequest from './makeValidatedGetRequest'
55
import { z } from 'zod'
66
import { gameActivitySchema } from '../entities/gameActivity'
77

8-
export default function useGameActivities(activeGame: Game) {
9-
const fetcher = async ([url]: [string]) => {
10-
const res = await makeValidatedGetRequest(url, z.object({
11-
activities: z.array(gameActivitySchema)
8+
export default function useGameActivities(activeGame: Game, page: number) {
9+
const fetcher = async ([url, page]: [string, number]) => {
10+
const qs = new URLSearchParams({
11+
page: String(page)
12+
}).toString()
13+
14+
const res = await makeValidatedGetRequest(`${url}?${qs}`, z.object({
15+
activities: z.array(gameActivitySchema),
16+
count: z.number(),
17+
itemsPerPage: z.number(),
18+
isLastPage: z.boolean()
1219
}))
1320

1421
return res
1522
}
1623

1724
const { data, error } = useSWR(
18-
[`/games/${activeGame.id}/game-activities`],
25+
[`/games/${activeGame.id}/game-activities`, page],
1926
fetcher
2027
)
2128

2229
return {
2330
activities: data?.activities ?? [],
31+
count: data?.count,
32+
itemsPerPage: data?.itemsPerPage,
33+
isLastPage: data?.isLastPage,
2434
loading: !data && !error,
2535
error: error && buildError(error)
2636
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import useSWR from 'swr'
2+
import buildError from '../utils/buildError'
3+
import { Game } from '../entities/game'
4+
import makeValidatedGetRequest from './makeValidatedGetRequest'
5+
import { z } from 'zod'
6+
import { convertDateToUTC } from '../utils/convertDateToUTC'
7+
8+
export const newLeaderboardEntriesChartSchema = z.object({
9+
date: z.number(),
10+
leaderboards: z.record(z.number()),
11+
change: z.record(z.number())
12+
})
13+
14+
export function useNewLeaderboardEntriesChart(activeGame: Game, startDate: string, endDate: string) {
15+
const fetcher = async ([url]: [string]) => {
16+
const qs = new URLSearchParams({
17+
startDate: convertDateToUTC(startDate),
18+
endDate: convertDateToUTC(endDate)
19+
}).toString()
20+
21+
const res = await makeValidatedGetRequest(`${url}?${qs}`, z.object({
22+
data: z.array(newLeaderboardEntriesChartSchema),
23+
leaderboardNames: z.array(z.string())
24+
}))
25+
26+
return res
27+
}
28+
29+
const { data, error } = useSWR(
30+
activeGame && startDate && endDate ? [`/games/${activeGame.id}/charts/new-leaderboard-entries`, startDate, endDate] : null,
31+
fetcher
32+
)
33+
34+
return {
35+
leaderboards: data?.data ?? [],
36+
leaderboardNames: data?.leaderboardNames ?? [],
37+
loading: !data && !error,
38+
error: error && buildError(error)
39+
}
40+
}

src/api/useNewPlayersChart.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import useSWR from 'swr'
2+
import buildError from '../utils/buildError'
3+
import { Game } from '../entities/game'
4+
import makeValidatedGetRequest from './makeValidatedGetRequest'
5+
import { z } from 'zod'
6+
import { convertDateToUTC } from '../utils/convertDateToUTC'
7+
8+
export const playersChartPayloadSchema = z.object({
9+
date: z.number(),
10+
count: z.number(),
11+
change: z.number()
12+
})
13+
14+
export function useNewPlayersChart(activeGame: Game, startDate: string, endDate: string) {
15+
const fetcher = async ([url]: [string]) => {
16+
const qs = new URLSearchParams({
17+
startDate: convertDateToUTC(startDate),
18+
endDate: convertDateToUTC(endDate)
19+
}).toString()
20+
21+
const res = await makeValidatedGetRequest(`${url}?${qs}`, z.object({
22+
data: z.array(playersChartPayloadSchema)
23+
}))
24+
25+
return res
26+
}
27+
28+
const { data, error } = useSWR(
29+
activeGame && startDate && endDate ? [`/games/${activeGame.id}/charts/new-players`, startDate, endDate] : null,
30+
fetcher
31+
)
32+
33+
return {
34+
players: data?.data ?? [],
35+
loading: !data && !error,
36+
error: error && buildError(error)
37+
}
38+
}

src/api/usePlayerAuthActivities.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,34 @@ import { playerAuthActivitySchema } from '../entities/playerAuthActivity'
77
import canPerformAction, { PermissionBasedAction } from '../utils/canPerformAction'
88
import { AuthedUser } from '../state/userState'
99

10-
export default function usePlayerAuthActivities(activeGame: Game, user: AuthedUser, playerId?: string) {
11-
const fetcher = async ([url]: [string]) => {
12-
const res = await makeValidatedGetRequest(url, z.object({
13-
activities: z.array(playerAuthActivitySchema)
10+
export default function usePlayerAuthActivities(activeGame: Game, user: AuthedUser, playerId: string | undefined, page: number) {
11+
const fetcher = async ([url, page]: [string, number]) => {
12+
const qs = new URLSearchParams({
13+
page: String(page)
14+
}).toString()
15+
16+
const res = await makeValidatedGetRequest(`${url}?${qs}`, z.object({
17+
activities: z.array(playerAuthActivitySchema),
18+
count: z.number(),
19+
itemsPerPage: z.number(),
20+
isLastPage: z.boolean()
1421
}))
1522

1623
return res
1724
}
1825

1926
const { data, error } = useSWR(
2027
canPerformAction(user, PermissionBasedAction.VIEW_PLAYER_AUTH_ACTIVITIES) && playerId
21-
? [`/games/${activeGame.id}/players/${playerId}/auth-activities`]
28+
? [`/games/${activeGame.id}/players/${playerId}/auth-activities`, page]
2229
: null,
2330
fetcher
2431
)
2532

2633
return {
2734
activities: data?.activities ?? [],
35+
count: data?.count,
36+
itemsPerPage: data?.itemsPerPage,
37+
isLastPage: data?.isLastPage,
2838
loading: !data && !error,
2939
error: error && buildError(error)
3040
}

src/api/useStatGlobalValueChart.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import useSWR from 'swr'
2+
import buildError from '../utils/buildError'
3+
import { Game } from '../entities/game'
4+
import makeValidatedGetRequest from './makeValidatedGetRequest'
5+
import { z } from 'zod'
6+
import { convertDateToUTC } from '../utils/convertDateToUTC'
7+
8+
export const statGlobalValueChartSchema = z.object({
9+
date: z.number(),
10+
value: z.number(),
11+
change: z.number()
12+
})
13+
14+
export function useStatGlobalValueChart(activeGame: Game, internalName: string, startDate: string, endDate: string) {
15+
const fetcher = async ([url]: [string]) => {
16+
const qs = new URLSearchParams({
17+
startDate: convertDateToUTC(startDate),
18+
endDate: convertDateToUTC(endDate)
19+
}).toString()
20+
21+
const res = await makeValidatedGetRequest(`${url}?${qs}`, z.object({
22+
data: z.array(statGlobalValueChartSchema)
23+
}))
24+
25+
return res
26+
}
27+
28+
const { data, error } = useSWR(
29+
activeGame && internalName && startDate && endDate ? [`/games/${activeGame.id}/charts/global-stats/${internalName}`, startDate, endDate] : null,
30+
fetcher
31+
)
32+
33+
return {
34+
dataPoints: data?.data ?? [],
35+
loading: !data && !error,
36+
error: error && buildError(error)
37+
}
38+
}

src/api/useStatsActivityChart.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import useSWR from 'swr'
2+
import buildError from '../utils/buildError'
3+
import { Game } from '../entities/game'
4+
import makeValidatedGetRequest from './makeValidatedGetRequest'
5+
import { z } from 'zod'
6+
import { convertDateToUTC } from '../utils/convertDateToUTC'
7+
8+
export const statsActivityChartSchema = z.object({
9+
date: z.number(),
10+
stats: z.record(z.number()),
11+
change: z.record(z.number())
12+
})
13+
14+
export function useStatsActivityChart(activeGame: Game, startDate: string, endDate: string) {
15+
const fetcher = async ([url]: [string]) => {
16+
const qs = new URLSearchParams({
17+
startDate: convertDateToUTC(startDate),
18+
endDate: convertDateToUTC(endDate)
19+
}).toString()
20+
21+
const res = await makeValidatedGetRequest(`${url}?${qs}`, z.object({
22+
data: z.array(statsActivityChartSchema),
23+
statNames: z.array(z.string())
24+
}))
25+
26+
return res
27+
}
28+
29+
const { data, error } = useSWR(
30+
activeGame && startDate && endDate ? [`/games/${activeGame.id}/charts/stats-activity`, startDate, endDate] : null,
31+
fetcher
32+
)
33+
34+
return {
35+
stats: data?.data ?? [],
36+
statNames: data?.statNames ?? [],
37+
loading: !data && !error,
38+
error: error && buildError(error)
39+
}
40+
}

0 commit comments

Comments
 (0)