Skip to content

feat(achievements): show achievement rewards as XP - #6646

Merged
rebelchris merged 5 commits into
mainfrom
feat/achievement-xp-migration
Sep 11, 2026
Merged

feat(achievements): show achievement rewards as XP#6646
rebelchris merged 5 commits into
mainfrom
feat/achievement-xp-migration

Conversation

@rebelchris

@rebelchris rebelchris commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Why

Follows dailydotdev/daily-api#4265, which retires achievement points: achievements now grant XP into the same balance quests feed, so the level in Game Center and on the Highest level leaderboard already accounts for them. This side catches the UI up so users see one currency instead of two.

What

  • read Achievement.xp and AchievementSyncResult.xpGained / totalAchievementXp
  • every "pts" / "points" label becomes XP — achievement card, showcase, picker, compare, completion modal, sync modal counter, profile header, achievements snapshot card
  • drop the "Most achievement points" leaderboard from /users, now a strict subset of "Highest level"; /users/mostAchievementPoints permanently redirects there rather than 404ing on old bookmarks
  • achievement-scoped XP totals are named totalAchievementXp throughout (useProfileAchievements, Game Center summary), so they don't read as questDashboard.level.totalXp, which is the user's whole balance
  • the sync analytics event keeps points_gained alongside xp_gained so existing dashboards keep reporting

Game Center needed no change: its "Total XP" reads questDashboard.level.totalXp, which starts including achievements the moment the API ships.

Deploy order

Gate this on dailydotdev/daily-api#4265 being deployed, not merely merged. xp, xpGained and totalAchievementXp only exist there. If this ships first the whole achievements surface fails rather than degrading — profile, Game Center, every modal, sync and the snapshot card.

Follow-ups

  • points_gained is kept in the sync analytics event purely for dashboard continuity and has no removal date — worth a ticket alongside the API's deprecated-alias cleanup so it doesn't live forever.

Test plan

  • 8 touched suites pass: sortAchievements, AchievementCard, AchievementTrackerButton, AchievementPickerModal, AchievementsWidget, gameCenter, UsersLeaderboardStaticProps, GameCenterStaticProps
  • typecheck clean for every touched file (remaining errors are pre-existing on main in useUserExperienceForm.spec.tsx and transaction.spec.tsx)
  • eslint clean on the diff

🤖 Generated with Claude Code

Preview domain

https://feat-achievement-xp-migration.preview.app.daily.dev

Follows daily-api retiring achievement points: achievements now grant XP into
the same balance quests feed, so the level shown in Game Center and on the
Highest level leaderboard already accounts for them.

- read Achievement.xp and AchievementSyncResult.xpGained/totalXp
- every "pts" / "points" label becomes XP, including the sync modal counter and
  the achievements snapshot card
- drop the Most achievement points leaderboard, now a strict subset of
  Highest level
- the sync analytics event keeps points_gained alongside xp_gained so existing
  dashboards keep reporting

Requires the API change to be deployed first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
daily-webapp Ready Ready Preview Sep 11, 2026 1:44pm UTC

Request Review

…ed board

Review follow-ups on the API rename:

- AchievementSyncResult.totalXp is now totalAchievementXp, matching daily-api.
  The same collision existed client side, so useProfileAchievements and the
  Game Center summary rename too — all three count achievement XP only, while
  questDashboard.level.totalXp is the whole balance.
- /users/mostAchievementPoints permanently redirects to /users/highestLevel
  instead of 404ing, since that board is the superset this PR retires it for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@rebelchris rebelchris left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-checked against the current head (84d44bf, after the merge from main). This looks clean: the points-to-XP rename is applied consistently across the GraphQL layer, the leaderboard config, the widgets, and the tests, and the retired mostAchievementPoints slug now issues a permanent redirect to /users/highestLevel rather than 404ing.

Deploy-ordering gate (main actionable item)

packages/shared/src/graphql/user/achievements.ts now selects xp on Achievement and xpGained / totalAchievementXp on the sync result. Those fields only exist in dailydotdev/daily-api#4265, which is still open and unmerged as of this review. If this PR ships first, ACHIEVEMENTS_QUERY and SYNC_ACHIEVEMENTS_MUTATION will fail schema validation on the live API. The highestLevel leaderboard has a isHighestLevelSchemaMissing fallback in pages/users/[id].tsx, but the achievements queries have no equivalent. Suggest holding this until #4265 is merged and deployed, or noting the dependency in the PR description so it is not merged out of order.

Minor notes

  • AchievementSyncModal.tsx still emits points_gained alongside xp_gained (set to the same value, for legacy dashboards). Worth adding a removal date or a tracking ticket in the comment so it does not linger indefinitely.
  • No leftover references to mostAchievementPoints, totalPoints, or pointsGained remain at head, apart from the intentional RETIRED_ACHIEVEMENT_POINTS_SLUG constant used for the redirect.

This review was generated by Smith, daily.dev's AI assistant, on behalf of the requester.

rebelchris and others added 2 commits September 11, 2026 15:39
…sModal

typecheck_strict_changed failed on CI: touching this file for the XP copy
pulled it into the changed set, and the strict gate then surfaced two
violations that predate this PR.

- handleClose took an optional event but onRequestClose requires one; both call
  sites always pass an event, so drop the optional marker rather than widen the
  contract
- ProfilePicture requires a user and useAuthContext().user is optional, so only
  render the avatar when there is one — the name beside it already falls back
  to "You"

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rebelchris
rebelchris merged commit 9a3d6e5 into main Sep 11, 2026
11 checks passed
@rebelchris
rebelchris deleted the feat/achievement-xp-migration branch September 11, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant