Skip to content

Comments

fix: account link in dashboard user drop down#18

Open
pax2678 wants to merge 5 commits intomichaelshimeles:mainfrom
pax2678:fix/account-navigate-to-clerk
Open

fix: account link in dashboard user drop down#18
pax2678 wants to merge 5 commits intomichaelshimeles:mainfrom
pax2678:fix/account-navigate-to-clerk

Conversation

@pax2678
Copy link

@pax2678 pax2678 commented Sep 2, 2025

The "Account" link in the dashboard user dropdown will use Clerk's openUserProfile() function, which is exactly the same mechanism that the homepage "Manage account" link uses through the UserButton component.

Summary of Changes:

Updated app/components/dashboard/nav-user.tsx:

Added openUserProfile import from useClerk hook
Added click handler to Account dropdown item that calls openUserProfile()
Result:

✅ Dashboard Account link now opens Clerk's UserProfile modal (same as homepage "Manage account")
✅ Consistent behavior between homepage and dashboard user account access
✅ Uses Clerk's native functionality rather than custom routing
Now when users click "Account" in the dashboard user dropdown, it will open the same Clerk Account Profile page that appears when clicking "Manage account" from the homepage user button dropdown.


Summary by cubic

Aligns the dashboard Account link with the homepage by opening Clerk’s UserProfile modal. Also cleans up Settings navigation and fixes subscription metadata/retrieval for accurate pricing.

  • Bug Fixes
    • Account: dropdown now calls openUserProfile() to open Clerk’s UserProfile.
    • Settings: fixed dropdown navigation to /dashboard/settings; removed duplicate sidebar link.
    • Subscriptions: removed priceId from checkout metadata, select latest subscription when querying, and update polarPriceId on webhook updates.

Summary by CodeRabbit

  • New Features

    • Account menu now opens the user profile directly and links Settings to the dashboard Settings page.
  • Bug Fixes

    • Improved subscription status reliability by consistently using the most recent subscription record.
  • Chores

    • Removed the redundant Settings item from the sidebar’s secondary navigation.
    • Streamlined subscription metadata handling for checkout and updates.

pax2678 added 5 commits July 10, 2025 14:30
…dated in Polar. Select the latest subscription when querying subscription based on userId.
…. priceId is not updated after a user changes the subscription creating confusion.

Changes Summary:

Checkout Creation (lines
  52-54):
  - REMOVED: priceId:
  productPriceId, from the metadata
   object
  - RESULT: Metadata now only
  contains userId when creating
  Polar checkouts

Impact:

  - Polar subscriptions: Will only
  store userId in metadata (no
  priceId)
  - Convex subscriptions: Will only
   store userId in metadata (no
  priceId)
  - Price tracking: Still works via
   the polarPriceId field in the
  subscription record
  - User linking: Preserved via
  userId in metadata for webhook
  processing
Changes Made:

  - Removed duplicate Settings link from sidebar
  navigation
    - Eliminated redundant Settings entry in navSecondary
  array in app-sidebar.tsx
  - Fixed Settings link in user dropdown navigation
    - Added proper routing to Settings dropdown item in
  nav-user.tsx
    - Settings link now navigates to /dashboard/settings
  when clicked
    - Used asChild pattern with React Router Link for
  proper navigation

  Result:

  - Eliminates confusing duplicate Settings links in
  dashboard
  - Provides single, functional Settings access through
  user dropdown
  - Improves user experience with cleaner navigation
  structure
The "Account" link in the dashboard user
  dropdown will use Clerk's openUserProfile() function,
  which is exactly the same mechanism that the homepage
  "Manage account" link uses through the UserButton
  component.

  Summary of Changes:

  Updated app/components/dashboard/nav-user.tsx:
  1. Added openUserProfile import from useClerk hook
  2. Added click handler to Account dropdown item that
  calls openUserProfile()

  Result:
  - ✅ Dashboard Account link now opens Clerk's
  UserProfile modal (same as homepage "Manage account")
  - ✅ Consistent behavior between homepage and dashboard
  user account access
  - ✅ Uses Clerk's native functionality rather than
  custom routing

  Now when users click "Account" in the dashboard user
  dropdown, it will open the same Clerk Account Profile
  page that appears when clicking "Manage account" from
  the homepage user button dropdown.
@vercel
Copy link

vercel bot commented Sep 2, 2025

@pax2678 is attempting to deploy a commit to the Goshen Labs Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Sep 2, 2025

Walkthrough

Removes the Settings item from the dashboard’s secondary navigation. Updates the user menu: Account opens the Clerk profile; Settings links to /dashboard/settings via a router Link. Adjusts subscription logic to fetch the latest subscription with descending order and augments webhook handling to store polarPriceId; removes priceId from checkout metadata.

Changes

Cohort / File(s) Summary
Dashboard navigation and user menu
app/components/dashboard/app-sidebar.tsx, app/components/dashboard/nav-user.tsx
Sidebar: removed secondary Settings nav item (empty array). User menu: imports Link, uses openUserProfile for Account, and renders Settings as a Link to /dashboard/settings via DropdownMenuItem asChild.
Subscriptions flow adjustments
convex/subscriptions.ts
Removed priceId from checkout metadata. For user subscription lookups, added descending order to return the most recent record. On subscription.updated webhook, patches subscription with polarPriceId from event payload.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Dashboard UI
  participant Clerk as Clerk SDK
  participant Router as App Router
  participant Svc as Subscriptions Service
  participant DB as Subscriptions DB
  participant WH as Webhook Handler

  rect rgb(237,245,255)
  note over UI: User dropdown interactions
  User->>UI: Open user menu
  UI->>Clerk: Account clicked -> openUserProfile()
  UI->>Router: Settings clicked -> navigate /dashboard/settings
  end

  rect rgb(240,255,240)
  note over Svc,DB: Subscription lookup (latest)
  UI->>Svc: checkUserSubscriptionStatus(userId)
  Svc->>DB: query subscriptions for userId<br/>order desc, take first
  DB-->>Svc: latest subscription
  Svc-->>UI: status/result
  end

  rect rgb(255,250,235)
  note over WH,DB: Webhook update
  alt subscription.updated
    WH->>DB: patch subscription with polarPriceId = event.price_id
  else other events
    WH->>WH: handle as before
  end
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • SSR #5 — Also modifies subscription status checks and navigation/Settings handling, indicating overlapping logic and routing adjustments.

Poem

In sidebars trimmed, a link took flight,
The user menu gleams just right.
Profiles pop with a gentle click,
Settings route is clean and slick.
Subscriptions sort from newest thread—
Webhooks tag the price instead.
A happy hop—release ahead! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@qodo-code-review
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 Security concerns

Potential sensitive data exposure:
The console.log of checkout data may include customerEmail and metadata. Consider removing or sanitizing logs in production environments.

⚡ Recommended focus areas for review

Index Ordering Assumption

The new .order("desc") relies on the default sort key of the "subscriptions" index. Confirm that the index's first sort field matches the intended recency (e.g., createdAt) and that descending order is supported; otherwise results may be non-deterministic or incorrect.

const subscription = await ctx.db
  .query("subscriptions")
  .withIndex("userId", (q) => q.eq("userId", user.tokenIdentifier))
  .order("desc")  // Order by createdAt in descending order
  .first();
Router Import

Using Link from "react-router" may not match the rest of the app if it relies on "react-router-dom" in a web context; ensure consistency with existing router imports to avoid runtime issues.

import { Link } from "react-router";
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar";
Logging Sensitive Data

The checkout creation still logs checkout data; verify that potentially sensitive fields (emails, metadata) are not exposed in server logs, especially in production.

console.log(
  "Creating checkout with data:",

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Ensure deterministic latest subscription

Using order("desc") on an index keyed only by userId doesn’t guarantee you’ll
get the most recent subscription in Convex; ordering will follow the index keys,
not creation time. Define and use a composite index (e.g.,
by_userId_creationTime on ["userId", "_creationTime"] or by_userId_periodStart)
and query it with .order("desc").first() to reliably select the latest record in
all three call sites, optionally filtering for active status where needed.

Examples:

convex/subscriptions.ts [197-201]
    const subscription = await ctx.db
      .query("subscriptions")
      .withIndex("userId", (q) => q.eq("userId", user.tokenIdentifier))
      .order("desc")  // Order by createdAt in descending order
      .first();
convex/subscriptions.ts [234-238]
    const subscription = await ctx.db
      .query("subscriptions")
      .withIndex("userId", (q) => q.eq("userId", user.tokenIdentifier))
      .order("desc")  // Order by createdAt in descending order
      .first();

Solution Walkthrough:

Before:

// in convex/subscriptions.ts

// In multiple query functions:
const subscription = await ctx.db
  .query("subscriptions")
  .withIndex("userId", (q) => q.eq("userId", user.tokenIdentifier))
  .order("desc")  // This does not guarantee ordering by creation time
  .first();

const hasActiveSubscription = subscription?.status === "active";
return { hasActiveSubscription };

After:

// in convex schema definition:
// defineTable({ ... }).index("by_userId_creationTime", ["userId", "_creationTime"])

// in convex/subscriptions.ts

// In multiple query functions:
const subscription = await ctx.db
  .query("subscriptions")
  .withIndex("by_userId_creationTime", (q) => q.eq("userId", user.tokenIdentifier))
  .order("desc") // Correctly orders by _creationTime
  .first();

const hasActiveSubscription = subscription?.status === "active";
return { hasActiveSubscription };
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical bug where fetching the latest subscription is not guaranteed, which could lead to incorrect user access. The proposed fix using a composite index is the correct and robust solution.

High
Possible issue
Use correct index for latest-first

.order("desc") sorts by the active index, not by "createdAt" here, so this won't
guarantee the latest subscription. Use a composite index that includes
_creationTime (e.g., "by_userId_creationTime") and order by desc to reliably
fetch the newest record. Apply this change to all three subscription queries
that intend to get the latest subscription.

convex/subscriptions.ts [197-201]

 const subscription = await ctx.db
   .query("subscriptions")
-  .withIndex("userId", (q) => q.eq("userId", user.tokenIdentifier))
-  .order("desc")  // Order by createdAt in descending order
+  .withIndex("by_userId_creationTime", (q) => q.eq("userId", user.tokenIdentifier))
+  .order("desc") // Order by _creationTime (latest first)
   .first();
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical bug where .order("desc") on the userId index does not sort by creation time, and provides the correct approach to fetch the latest subscription.

High
General
Correct Link import source

For web apps, import Link from react-router-dom to ensure it binds to the
correct router context and avoids navigation issues. Align this with the router
provider used in your app.

app/components/dashboard/nav-user.tsx [8]

-import { Link } from "react-router";
+import { Link } from "react-router-dom";
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly points out that for a web application, Link should be imported from react-router-dom instead of react-router to prevent potential navigation issues.

Medium
  • More

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
app/components/dashboard/nav-user.tsx (1)

85-89: Prefer onSelect over onClick for menu item activation

Radix-based menus fire onSelect for both mouse and keyboard. This improves a11y and avoids edge cases with focus management.

-              <DropdownMenuItem onClick={() => openUserProfile()}>
+              <DropdownMenuItem onSelect={() => openUserProfile()}>
                 <IconUserCircle />
                 Account
               </DropdownMenuItem>
convex/subscriptions.ts (2)

237-238: Repeat: fix comment and validate ordering on this query

Same clarification as above; ensure the intended “latest subscription” is returned.

-      .order("desc")  // Order by createdAt in descending order
+      .order("desc")  // Order by _creationTime in descending order (latest first)

265-266: Repeat: fix comment and confirm latest-first behavior

Align the comment and double-check index capabilities here as well.

-      .order("desc")  // Order by createdAt in descending order
+      .order("desc")  // Order by _creationTime in descending order (latest first)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a3f7c3e and b1bdb4b.

📒 Files selected for processing (3)
  • app/components/dashboard/app-sidebar.tsx (1 hunks)
  • app/components/dashboard/nav-user.tsx (3 hunks)
  • convex/subscriptions.ts (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
app/components/dashboard/app-sidebar.tsx (2)
app/components/dashboard/nav-secondary.tsx (2)
  • NavSecondary (15-58)
  • item (31-53)
app/routes/dashboard/settings.tsx (1)
  • Page (4-16)
convex/subscriptions.ts (1)
app/routes/pricing.tsx (1)
  • priceId (57-97)
app/components/dashboard/nav-user.tsx (3)
app/components/ui/dropdown-menu.tsx (1)
  • DropdownMenuItem (248-248)
app/routes/dashboard/settings.tsx (1)
  • Page (4-16)
app/components/homepage/navbar.tsx (1)
  • loaderData (16-174)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (5)
app/components/dashboard/app-sidebar.tsx (1)

29-29: Settings removed from sidebar — confirm discoverability and product intent

With navSecondary now empty, Settings is only reachable from the user menu. If that’s intentional, we're good; otherwise consider keeping a secondary entry or adding a tooltip/inline hint. Also verify no docs/screens reference the old sidebar Settings link.

app/components/dashboard/nav-user.tsx (3)

35-35: Good switch to Clerk’s openUserProfile

Using openUserProfile aligns with Clerk best practices and the PR goal. No issues.


89-95: Settings link composition looks good

DropdownMenuItem asChild + Link is the right pattern; route consistency with /dashboard/settings is maintained.


35-35: Scope note: PR includes non-menu changes

This PR also modifies sidebar nav (removing Settings) and Convex subscription queries/webhook patching. If feasible, split UI nav changes and billing/backend changes into separate PRs for easier review and rollback.

convex/subscriptions.ts (1)

333-345: Persisting polarPriceId on update — looks correct

Updating polarPriceId on subscription.updated aligns the record with Polar’s current price linkage. No issues spotted.

Comment on lines +200 to 201
.order("desc") // Order by createdAt in descending order
.first();
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ordering semantics: clarify and confirm index support

.order("desc") on a Convex query orders by the index’s natural order (commonly _creationTime), not a createdAt field. The inline comment is misleading; also confirm the subscriptions table/index supports ordering with this query shape to avoid runtime errors.

-      .order("desc")  // Order by createdAt in descending order
+      .order("desc")  // Order by _creationTime in descending order (latest first)

Optionally verify schema/indexes with the script below.


🏁 Script executed:

#!/bin/bash
# Show subscriptions table indexes
rg -n -C3 'defineTable\(|\.index\(' convex | rg -n -C3 'subscriptions|userId|polarId|by_token'
# Locate schema definitions
fd -a schema -t f convex | xargs -I{} rg -n -C4 'subscriptions|index\(' {}

Length of output: 1952


Clarify ordering semantics on subscriptions query

File: convex/subscriptions.ts (lines 200–201)

-      .order("desc")  // Order by createdAt in descending order
+      .order("desc")  // Order by _creationTime in descending order (latest first)

The subscriptions table doesn’t define a createdAt field; .order() defaults to the internal _creationTime index.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.order("desc") // Order by createdAt in descending order
.first();
.order("desc") // Order by _creationTime in descending order (latest first)
.first();
🤖 Prompt for AI Agents
In convex/subscriptions.ts around lines 200–201, the call .order("desc") is
misleading because there is no createdAt field on the subscriptions table and
Convex will use the internal _creationTime by default; explicitly specify the
index by replacing the ambiguous ordering with .order("_creationTime", "desc")
and update the inline comment to state that ordering is by the internal
_creationTime (or alternatively add a createdAt column to the subscriptions
schema and order by that if you prefer a public timestamp).

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant