Conversation
WalkthroughAdds a Ranked branch to player stats: i18n entries, UI support for selecting Ranked and its subtypes, and an API schema change to store Ranked stats keyed by RankedType. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/client/components/baseComponents/stats/PlayerStatsTree.ts (1)
67-69: Avoid hard-codingRankedType.OneVOnehere.
src/core/ApiSchemas.ts:101-116exposes ranked stats as a record keyed byRankedType, andsrc/core/game/Game.ts:225-240already models the queue as an enum. This branch will silently ignore the next ranked type added there. Please keep a selected ranked type, or at least derive the first available ranked key fromstatsTree.Ranked.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts` around lines 67 - 69, The branch is hard-coded to use RankedType.OneVOne; update the logic to use a maintained selected ranked key (e.g., this.selectedRankedType) or derive the first available key from statsTree.Ranked instead of the literal RankedType.OneVOne. Modify the getter to return this.statsTree?.Ranked?.[this.selectedRankedType ?? (Object.keys(this.statsTree?.Ranked || {})[0] as unknown as RankedType)] ?? null and ensure selectedRankedType is initialized/kept in component state and typed as RankedType so newly added ranked types are honored automatically.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts`:
- Around line 67-69: The branch is hard-coded to use RankedType.OneVOne; update
the logic to use a maintained selected ranked key (e.g.,
this.selectedRankedType) or derive the first available key from statsTree.Ranked
instead of the literal RankedType.OneVOne. Modify the getter to return
this.statsTree?.Ranked?.[this.selectedRankedType ??
(Object.keys(this.statsTree?.Ranked || {})[0] as unknown as RankedType)] ?? null
and ensure selectedRankedType is initialized/kept in component state and typed
as RankedType so newly added ranked types are honored automatically.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1845eef0-b274-4427-9fa2-38963d6b1763
📒 Files selected for processing (3)
resources/lang/en.jsonsrc/client/components/baseComponents/stats/PlayerStatsTree.tssrc/core/ApiSchemas.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/client/components/baseComponents/stats/PlayerStatsTree.ts (1)
116-130: Remove the misleading type cast.Line 118 casts
selectedType as GameType, butselectedTypecan be"Ranked"which is not aGameType. The cast is unnecessary sincetypesis(GameType | "Ranked")[]andincludesaccepts the union type directly. The cast hides the actual type and could mask future type errors.♻️ Suggested fix
- if (types.length && !types.includes(this.selectedType as GameType)) { + if (types.length && !types.includes(this.selectedType)) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts` around lines 116 - 130, In syncSelection(), remove the misleading cast "selectedType as GameType" and call includes with the actual this.selectedType value (since availableTypes is (GameType | "Ranked")[] and includes accepts that union); update the check to use this.selectedType directly so the runtime check and TypeScript types align (refer to syncSelection, selectedType, and availableTypes).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts`:
- Around line 302-314: In PlayerStatsTree replace the raw enum label output (the
${r} inside the rankedTypes map) with a call to the translation helper so
displayed ranked type labels go through i18n; e.g., change the button body to
use translateText(`player_stats_tree.ranked_type.${r}`) (or a small mapping
function) while keeping the click handler setRankedType(r) and the
selectedRankedType comparison unchanged, and add corresponding keys like
player_stats_tree.ranked_type.1v1 to your locale JSON.
---
Nitpick comments:
In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts`:
- Around line 116-130: In syncSelection(), remove the misleading cast
"selectedType as GameType" and call includes with the actual this.selectedType
value (since availableTypes is (GameType | "Ranked")[] and includes accepts that
union); update the check to use this.selectedType directly so the runtime check
and TypeScript types align (refer to syncSelection, selectedType, and
availableTypes).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c4a6a1fe-f13a-4c65-8006-4388901a2a3c
📒 Files selected for processing (1)
src/client/components/baseComponents/stats/PlayerStatsTree.ts
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/client/components/baseComponents/stats/PlayerStatsTree.ts (1)
38-82: Consolidate RankedType metadata into a single source of truth.The code currently distributes Ranked subtype knowledge across three places:
availableRankedTypes()filters keys,labelForRankedType()maps types to translation keys via switch, andavailableTypes()checks raw key count. If one place changes alone, the UI can drift—for example, a Ranked tab visible with no subtype buttons, or a subtype with no label.Additionally,
labelForRankedType()lacks a default case and can returnundefinedif called with an unexpected value.Define a single
Record<RankedType, string>for all Ranked metadata:♻️ Proposed refactor
+ private readonly rankedTypeLabels: Record<RankedType, string> = { + [RankedType.OneVOne]: "player_stats_tree.ranked_1v1", + }; + private get availableTypes(): (GameType | "Ranked")[] { if (!this.statsTree) return []; const types: (GameType | "Ranked")[] = Object.keys(this.statsTree).filter( (k): k is GameType => isGameType(k) && Object.keys(this.statsTree![k as GameType] ?? {}).length > 0, ); - if ( - this.statsTree.Ranked && - Object.keys(this.statsTree.Ranked).length > 0 - ) { + if (this.availableRankedTypes.length > 0) { types.push("Ranked"); } return types; } private get availableRankedTypes(): RankedType[] { if (!this.statsTree?.Ranked) return []; - return Object.keys(this.statsTree.Ranked).filter((k): k is RankedType => - Object.values(RankedType).includes(k as RankedType), - ); + return Object.keys(this.statsTree.Ranked).filter( + (k): k is RankedType => k in this.rankedTypeLabels, + ); } private labelForRankedType(r: RankedType) { - switch (r) { - case RankedType.OneVOne: - return translateText("player_stats_tree.ranked_1v1"); - } + return translateText(this.rankedTypeLabels[r]); }All current
RankedTypemembers (OneVOne) have matching translation keys (player_stats_tree.ranked_1v1) inresources/lang/en.json.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts` around lines 38 - 82, Consolidate RankedType logic by introducing a single Record constant (e.g., RANKED_METADATA: Record<RankedType, string>) mapping each RankedType to its translation key and then update availableRankedTypes, labelForRankedType, and availableTypes to derive behavior from that map: have availableRankedTypes return keys present in statsTree.Ranked filtered against Object.keys(RANKED_METADATA), change availableTypes to check for any keys from RANKED_METADATA instead of raw key count, and rewrite labelForRankedType to look up the translation key in RANKED_METADATA and return a safe fallback if missing (avoid a missing default/undefined). Use the existing symbols availableRankedTypes, labelForRankedType, availableTypes, and RankedType to locate and replace the logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/client/components/baseComponents/stats/PlayerStatsTree.ts`:
- Around line 38-82: Consolidate RankedType logic by introducing a single Record
constant (e.g., RANKED_METADATA: Record<RankedType, string>) mapping each
RankedType to its translation key and then update availableRankedTypes,
labelForRankedType, and availableTypes to derive behavior from that map: have
availableRankedTypes return keys present in statsTree.Ranked filtered against
Object.keys(RANKED_METADATA), change availableTypes to check for any keys from
RANKED_METADATA instead of raw key count, and rewrite labelForRankedType to look
up the translation key in RANKED_METADATA and return a safe fallback if missing
(avoid a missing default/undefined). Use the existing symbols
availableRankedTypes, labelForRankedType, availableTypes, and RankedType to
locate and replace the logic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2b824325-7ca8-465a-bac7-519f182a5758
📒 Files selected for processing (2)
resources/lang/en.jsonsrc/client/components/baseComponents/stats/PlayerStatsTree.ts
✅ Files skipped from review due to trivial changes (1)
- resources/lang/en.json
## Description: openfrontio/infra#279 to go with this, splits out 1v1 ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: w.o.n
Description:
https://github.com/openfrontio/infra/pull/279 to go with this, splits out 1v1
Please complete the following:
Please put your Discord username so you can be contacted if a bug or regression is found:
w.o.n