feat: Lifetime leaderboard tab — unique postboxes claimed#85
Merged
Conversation
Tapping the James strip immediately slides it out rather than waiting up to 8 s for the auto-dismiss timer. Prevents the strip from blocking the Claim button on the Claim screen while James is speaking. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace `as Map<String, dynamic>?` casts on Firestore array entries with `is Map` checks so malformed backend data doesn't throw a CastError. Entries are always maps in practice; this is purely defensive. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the raw UID title/subtitle with the user's display name. While the name is loading a spinner shows in the avatar and the title reads "Loading...". Once resolved the display name is shown with two-letter initials; if the profile has no displayName the title falls back to "Unknown player". The raw Firebase UID is no longer shown to the user anywhere in the friends list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: updateLifetimeLeaderboard() in _leaderboardUtils.ts tracks
uniquePostboxesClaimed + totalPoints in leaderboards/lifetime
- startScoring: uniqueness check via prior-claim query; FieldValue.increment
on users/{uid}.uniquePostboxesClaimed + lifetimePoints
- updateDisplayName: propagates name change to leaderboards/lifetime
- Flutter: Lifetime tab in LeaderboardScreen (4th tab); displays
"N box(es) · M pts" format; James strip explains the list on tab switch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
updateLifetimeLeaderboard()in_leaderboardUtils.tsmaintainsleaderboards/lifetimedocument (sorted byuniquePostboxesClaimeddesc, top 100)startScoring: after each claim session, queries prior claims to detect new unique boxes, incrementsuniquePostboxesClaimed+lifetimePointsonusers/{uid}viaFieldValue.increment, then pushes to lifetime leaderboardupdateDisplayName: propagates display name changes toleaderboards/lifetimeas it already does for the periodic tabsLeaderboardScreen; trailing shows"N box(es) · M pts"; Postman James slides up with an explanation when the tab is selectedData model
users/{uid}gains two server-write-only fields:uniquePostboxesClaimed: number— deduplicated; same box on a different day doesn't incrementlifetimePoints: number— cumulative points from all claims since feature launchleaderboards/lifetimedocument mirrors the same structure as other periods but withperiodKey: "lifetime"(no rollover) andentries[].uniquePostboxesClaimed/entries[].totalPointsinstead ofentries[].points.Test plan
cd functions && npx tsc --noEmit— cleanflutter test— 58/58 passleaderboards/lifetimedocument created with correct entryuniquePostboxesClaimedstays,lifetimePointsincreasesuniquePostboxesClaimedincrementsleaderboards/lifetimeupdates"1 box · N pts"(singular) /"3 boxes · M pts"(plural)🤖 Generated with Claude Code