Skip to content

Feature: Add Google OAuth for Leaderboard Name Claiming#2

Open
threehymns wants to merge 5 commits into
feature/convex-leaderboardfrom
feature/add-google-oauth-convex-7346118070983662753
Open

Feature: Add Google OAuth for Leaderboard Name Claiming#2
threehymns wants to merge 5 commits into
feature/convex-leaderboardfrom
feature/add-google-oauth-convex-7346118070983662753

Conversation

@threehymns
Copy link
Copy Markdown
Owner

Added an account system to allow users to sign in with Google using @convex-dev/auth. Users can now claim a display name when logged in, which retroactively attaches all their old anonymous scores to their account. If a name is already claimed, other anonymous users are prevented from submitting scores with it, ensuring leaderboard integrity.


PR created automatically by Jules for task 7346118070983662753 started by @threehymns

- Installed `@convex-dev/auth` and `@auth/core`.
- Configured Convex Google OAuth and user tables.
- Added a `UserMenu` to login/logout using Google.
- Implemented `claimName` endpoint to claim custom display names and associate past anonymous scores with the user's account.
- Prevent anonymous users from submitting scores with claimed names.

Co-authored-by: threehymns <70611435+threehymns@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 27, 2026

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

Project Deployment Actions Updated (UTC)
matchfield Ready Ready Preview, Comment Apr 28, 2026 7:37pm

@ghost
Copy link
Copy Markdown

ghost commented Apr 27, 2026

Rooviewer Clock   See task

Found 4 issues to address before merging:

  • UserMenu is imported in App.tsx but never rendered -- sign-in/out UI is invisible to users
  • claimName is skipped for first-time logged-in users (userName === null), leaving their chosen name unprotected
  • Score migration in claimName does a full table scan via .filter().collect() -- needs a playerName index
  • resend dependency added to package.json but never used

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

Comment thread App.tsx
import SettingsPage from './components/SettingsPage';
import GameModeScreen from './components/GameModeScreen';
import Leaderboard from './components/Leaderboard';
import { UserMenu } from './components/UserMenu';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

UserMenu is imported here but never rendered in the component's JSX. The sign-in/sign-out UI won't be visible to users, which defeats the purpose of this PR. You likely need to add <UserMenu /> somewhere in the returned markup (e.g. alongside the other top-level UI elements).

Fix it with Roo Code or mention @roomote and request a fix.

Comment thread components/VictoryModal.tsx Outdated
localStorage.setItem('matchfield-player-name', trimmedName);

// If user is logged in but hasn't claimed a name or is changing it
if (userName !== undefined && userName !== null && userName !== trimmedName) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This condition skips claimName when userName === null, which is the state for a logged-in user who hasn't claimed a name yet. On their first score submission the name is never claimed, so it remains unprotected and another user could later claim it. The condition should also handle the userName === null case, e.g.:

Suggested change
if (userName !== undefined && userName !== null && userName !== trimmedName) {
if (userName !== undefined && userName !== trimmedName) {

Fix it with Roo Code or mention @roomote and request a fix.

Comment thread convex/users.ts
Comment on lines +49 to +52
const allScoresForName = await ctx.db
.query("leaderboard")
.filter((q) => q.eq(q.field("playerName"), trimmedName))
.collect();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This .filter().collect() does a full table scan of the leaderboard since there's no index on playerName. If the leaderboard grows, this will get increasingly expensive. Consider adding a by_playerName index to the leaderboard table in the schema and using .withIndex() here instead.

Fix it with Roo Code or mention @roomote and request a fix.

Comment thread package.json Outdated
"lucide-react": "^0.552.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"resend": "^6.12.2",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

resend is added as a dependency but is never imported or used anywhere in the codebase. This adds unnecessary weight to node_modules. If it's not needed for a planned email flow, it should be removed.

Fix it with Roo Code or mention @roomote and request a fix.

…to sign in after an anonymous score is recorded. Here is a summary of the changes I've made:

- I added a prompt inside `VictoryModal` for anonymous users to sign in with Google immediately after logging a score, allowing them to claim their entered name permanently.
- I fixed a bug that caused anonymous users to hit an authentication error when trying to save scores by properly handling `null` user values.
- I updated the error display to render a clickable "Sign in with Google" button when a name collision error occurs.
- I resolved a backend bug in `claimName` caused by filtering on `undefined` userIds.

Co-authored-by: threehymns <70611435+threehymns@users.noreply.github.com>
- Updated the `UserMenu` on the homepage to be a very subtle text link instead of a solid button block per user request.

Co-authored-by: threehymns <70611435+threehymns@users.noreply.github.com>
- Fixed a bug where first-time logged-in users couldn't claim a name due to `userName === null` being the only check. Now explicitly uses `isAuthenticated` from `useConvexAuth`.
- Optimized the `claimName` migration of anonymous scores by utilizing a new `by_playerName` index in the `leaderboard` table instead of doing a full table scan.
- Cleaned up package.json by removing unused `resend` and `@oslojs/crypto` dependencies.

Co-authored-by: threehymns <70611435+threehymns@users.noreply.github.com>
- Restored `UserMenu` in `App.tsx` which was accidentally missing.
- Refactored `currentUserName` to `currentUserDetails` to return the user's `image` along with their name.
- Modified `UserMenu` to display the user's avatar image if it exists, alongside their name, in a small pill, that wraps them inside an anchor tag linking to `/profile`.

Co-authored-by: threehymns <70611435+threehymns@users.noreply.github.com>
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