Skip to content

Commit c9eaca5

Browse files
authored
Merge pull request #476 from TaloDev/develop
Release 0.69.4
2 parents fcaebb6 + 31c6872 commit c9eaca5

25 files changed

+262
-247
lines changed

.github/workflows/docker.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ jobs:
2525
uses: docker/build-push-action@v5
2626
with:
2727
platforms: linux/amd64,linux/arm64
28-
push: true
28+
push: ${{ startsWith(github.ref, 'refs/tags/') }}
2929
tags: |
3030
ghcr.io/talodev/frontend:latest
3131
ghcr.io/talodev/frontend:${{ github.ref_name }}
32+
cache-from: type=gha
33+
cache-to: type=gha,mode=max
3234

3335
- name: Image digest
3436
run: echo ${{ steps.docker_build.outputs.digest }}

CLAUDE.md

Lines changed: 1 addition & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22

33
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44

5-
## Project Overview
6-
7-
Talo is a self-hostable game dev dashboard. This is the frontend React application that provides a web interface for managing players, leaderboards, events, stats, game saves, and other game backend features. The frontend communicates with the Talo backend API.
8-
95
## Development Commands
106

117
### Running the application
@@ -31,29 +27,6 @@ npm run cypress:open # Open Cypress (dev server must be running)
3127
npm run lint # Run Oxlint on src/**/*.{js,jsx,ts,tsx}
3228
```
3329

34-
### Testing Notes
35-
36-
- Unit tests use Vitest with jsdom environment
37-
- Test files are co-located with source in `__tests__/` directories
38-
- E2E tests are in `cypress/e2e/pages/` and use Cypress
39-
- Coverage excludes `src/api/`, `src/entities/`, `src/constants/`, and `src/utils/canViewPage.ts`
40-
- Tests must run with `TZ=UTC` for consistent date handling
41-
42-
## Architecture Overview
43-
44-
### Tech Stack
45-
46-
- React 18 with TypeScript
47-
- Vite for build tooling
48-
- React Router v6 for routing
49-
- Recoil for global state management
50-
- Axios for HTTP requests
51-
- SWR for data fetching and caching
52-
- Zod for runtime validation
53-
- Tailwind CSS v4 for styling
54-
- Recharts for charts
55-
- React Hook Form for forms
56-
5730
### Directory Structure
5831

5932
```
@@ -102,14 +75,7 @@ src/
10275
- `devDataState` - Dev data inclusion flag
10376
- State consumed via `useRecoilValue()`, `useRecoilState()`, `useSetRecoilState()`
10477

105-
### API Layer
106-
107-
- Base Axios instance configured in [src/api/api.ts](src/api/api.ts)
108-
- Request interceptor adds Bearer token and dev data header
109-
- Response interceptor handles 401s with automatic token refresh
110-
- Base URL from `VITE_API_URL` environment variable
111-
112-
**Data fetching patterns:**
78+
### Data fetching
11379

11480
1. **SWR hooks** (23 hooks): Pattern is `use{Entity}(game, params)` returning `{ data, loading, error }`
11581
- Examples: `useEvents`, `useLeaderboards`, `useStats`
@@ -120,77 +86,12 @@ src/
12086
- Uses `makeValidatedRequest()` wrapper for Zod validation
12187
- Returns validated, typed responses
12288

123-
### Component Patterns
124-
125-
- Functional components with TypeScript
126-
- Composition over inheritance
127-
- Context for cross-cutting concerns (EventsContext, ToastProvider)
128-
- Form handling with React Hook Form
129-
- Tables use composable system: `Table` > `TableHeader`/`TableBody` > `TableCell`
130-
131-
### Key Utilities and Hooks
132-
133-
Located in [src/utils/](src/utils/):
134-
135-
- `useTimePeriod` - Date range calculation from period strings ('1d', '7d', '30d', 'w', 'm', 'y')
136-
- `useTimePeriodAndDates` - Combined time period and date management
137-
- `useLocalStorage` - localStorage with React state sync
138-
- `usePlayer` - Extract player from URL params
139-
- `useSortedItems` - Client-side sorting
140-
- `useSearch` - Client-side search filtering
141-
- `useNodeGraph` - Graph visualization for save data (using @xyflow/react)
142-
- `buildError` - Normalize error objects
143-
- `canPerformAction` / `canViewPage` - Permission checking
144-
145-
## Important Patterns
146-
147-
### Authentication
148-
149-
- Managed by [AuthService](src/services/AuthService.ts) singleton
150-
- Token-based with automatic refresh on 401 responses
151-
- Token stored in memory (not localStorage for security)
152-
- Login redirects handled via `useIntendedRoute` hook
153-
15489
### Authorization
15590

15691
- Route-level checks with `canViewPage()` in Router
15792
- Action-level checks with `canPerformAction()` throughout components
15893
- Based on user type (ADMIN, OWNER, DEV, DEMO)
15994

160-
### Validation
161-
162-
- Zod schemas defined alongside entities in [src/entities/](src/entities/)
163-
- `makeValidatedRequest()` and `makeValidatedGetRequest()` wrappers ensure type safety
164-
- Validation errors logged and sent to Sentry
165-
166-
### Error Handling
167-
168-
- Centralized error normalization via `buildError()`
169-
- API errors show user-friendly messages via toast notifications
170-
- Sentry integration for error tracking
171-
172-
### Date Handling
173-
174-
- All API dates must be UTC
175-
- Use `convertDateToUTC()` when sending dates to API
176-
- Tests run with `TZ=UTC` to ensure consistency
177-
178-
### Active Game Context
179-
180-
- Most features require an active game to be selected
181-
- Active game stored in Recoil state and persisted to localStorage
182-
- Routes conditionally render based on `activeGame` availability
183-
184-
## Environment Variables
185-
186-
Required environment variables (set via `.env` files):
187-
188-
- `VITE_API_URL` - Backend API base URL (e.g., `http://localhost:3000`)
189-
190-
## Node Version
191-
192-
This project requires Node.js 24.x (see package.json engines).
193-
19495
## Git Workflow
19596

19697
Main branch for PRs: `develop`

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ COPY . .
66
# this prevents them from being substituted with empty values
77
RUN sed -i 's/\${/\\${/g' .env.production
88

9-
RUN npm install
9+
RUN --mount=type=cache,target=/root/.npm npm install
1010
RUN npm run build
1111

1212
FROM caddy:2-alpine

package-lock.json

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

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.69.3",
2+
"version": "0.69.4",
33
"license": "MIT",
44
"type": "module",
55
"scripts": {
@@ -26,9 +26,9 @@
2626
"axios": "^1.13.5",
2727
"chroma-js": "^3.2.0",
2828
"clsx": "^2.0.0",
29-
"dagre": "^0.8.5",
3029
"date-fns": "^2.29.3",
3130
"dinero.js": "^2.0.0-alpha.11",
31+
"elkjs": "^0.11.0",
3232
"framer-motion": "^10.9.1",
3333
"lodash-es": "^4.17.23",
3434
"prop-types": "^15.7.2",
@@ -54,7 +54,6 @@
5454
"@testing-library/react": "^15.0.4",
5555
"@testing-library/user-event": "^14.5.2",
5656
"@types/chroma-js": "^3.1.2",
57-
"@types/dagre": "^0.7.52",
5857
"@types/lodash-es": "^4.17.12",
5958
"@types/randomcolor": "^0.5.9",
6059
"@types/react": "^18.3.5",

src/api/useEventBreakdown.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default function useEventBreakdown(
1616
const qs = new URLSearchParams({
1717
eventName,
1818
startDate: convertDateToUTC(startDate),
19-
endDate: convertDateToUTC(endDate),
19+
endDate: convertDateToUTC(endDate, true),
2020
}).toString()
2121

2222
const res = await makeValidatedGetRequest(

src/api/useEvents.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default function useEvents(activeGame: Game, startDate: string, endDate:
1616
const fetcher = async ([url]: [string]) => {
1717
const qs = new URLSearchParams({
1818
startDate: convertDateToUTC(startDate),
19-
endDate: convertDateToUTC(endDate),
19+
endDate: convertDateToUTC(endDate, true),
2020
}).toString()
2121

2222
const res = await makeValidatedGetRequest(

src/api/useHeadlines.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default function useHeadlines(
3232
const fetcher = async ([url]: [string]) => {
3333
const qs = new URLSearchParams({
3434
startDate: convertDateToUTC(startDate),
35-
endDate: convertDateToUTC(endDate),
35+
endDate: convertDateToUTC(endDate, true),
3636
}).toString()
3737

3838
const headlines: (keyof Headlines)[] = [

src/api/useLeaderboardEntries.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export default function useLeaderboardEntries({
2525
const params: Record<string, string> = { page: String(page) }
2626
if (withDeleted) params.withDeleted = '1'
2727
params.startDate = convertDateToUTC(startDate)
28-
params.endDate = convertDateToUTC(endDate)
28+
params.endDate = convertDateToUTC(endDate, true)
2929
const qs = new URLSearchParams(params).toString()
3030

3131
const res = await makeValidatedGetRequest(

src/api/useNewLeaderboardEntriesChart.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function useNewLeaderboardEntriesChart(
1919
const fetcher = async ([url]: [string]) => {
2020
const qs = new URLSearchParams({
2121
startDate: convertDateToUTC(startDate),
22-
endDate: convertDateToUTC(endDate),
22+
endDate: convertDateToUTC(endDate, true),
2323
}).toString()
2424

2525
const res = await makeValidatedGetRequest(

0 commit comments

Comments
 (0)