mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-22 20:07:10 +00:00
feat(client): account usernames + verified badge on player-facing lists (#4653)
## Summary Client side of openfrontio/infra#436 — every player-facing GET now returns the player's **account username** next to their `publicId`, and this PR renders it everywhere, with a blue verified check for premium/indefinite bare-name holders. ### Schemas (all additive, `.nullable().optional()` — no deploy-order constraint) - `FriendEntry`, `PlayerProfile`: `username` - `ClanMember`, `ClanJoinRequest`: `username`; `ClanBan`: `username` + `bannedByUsername` - `RankedLeaderboardEntry`: `accountUsername` (the existing session `username` field is untouched) ### `<player-name>` element One component owns player-identity rendering on account surfaces: - displays `username ?? publicId` - click-to-copy copies the **username when set**, the publicId otherwise; `copyText` overrides (profile modal copies the share URL) - `onNameClick` replaces copying with an action (clan member rows + leaderboard rows open the player's profile); `nameClass` overrides the chip styling so leaderboard names keep their original bold look - appends the verified check (same mark as the username-row toggle) when `isVerifiedUsername(username)` Used by: friends list + requests, all clan member/request/ban rows (bans badge both the banned player and the issuing officer), ranked leaderboard rows + sticky self row (showing `accountUsername ?? public_id` — the session name is deliberately dropped ahead of its API removal), profile modal header. ### Verified inference No API flag needed: account-username bases can never contain dots, so a dotless display name **is** the bare-name claim (premium/indefinite). `TEMPORARY####` server renames are excluded, matching the play-toggle eligibility rule. The leaderboard derives the badge from `accountUsername` only — session names are free-form and would false-positive. Also: clan member/request/ban search filters now match usernames, not just publicIds, and sending a friend request refetches the request lists instead of inserting the raw input (which may be a username, not a publicId). ## Test plan - [x] `npm test` — full suite green (2087 + 176 server) - [x] New schema tests: each field's set / null / absent states; `accountUsername` coexists with session `username` - [x] `isVerifiedUsername` unit tests (bare / suffixed / null / TEMPORARY) - [x] tsc, ESLint, Prettier clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
"no_stats": "No stats available yet. Play some games to start tracking.",
|
||||
"not_found": "Not Found",
|
||||
"or": "OR",
|
||||
"public_player_id": "Public Player ID:",
|
||||
"public_player_id": "Public ID:",
|
||||
"reactivate_subscription": "Reactivate",
|
||||
"recovery_email_sent": "Recovery email sent to {email}",
|
||||
"reward_daily": "Daily subscription reward",
|
||||
@@ -544,7 +544,7 @@
|
||||
"no_friends": "You haven't added any friends yet.",
|
||||
"outgoing": "Outgoing",
|
||||
"pending_requests": "Pending Requests",
|
||||
"public_id_placeholder": "Enter their public player ID",
|
||||
"public_id_placeholder": "Enter their username or player ID",
|
||||
"remove": "Remove",
|
||||
"request_accepted": "Friend request accepted",
|
||||
"request_auto_accepted": "Friend request accepted — you are now friends",
|
||||
@@ -1624,6 +1624,7 @@
|
||||
"too_long": "Username must not exceed {max} characters.",
|
||||
"too_short": "Username must be at least {min} characters long.",
|
||||
"verified_heading": "Verified name",
|
||||
"verified_player": "Verified player",
|
||||
"verified_sub_required": "You need an active subscription to play under your verified name.",
|
||||
"verified_sub_required_confirm": "View store",
|
||||
"verified_toggle": "Verified"
|
||||
|
||||
Reference in New Issue
Block a user