Skip to content

Conversation

GiselleNessi
Copy link
Contributor

@GiselleNessi GiselleNessi commented Aug 21, 2025


PR-Codex overview

This PR introduces a new feature for collecting user feedback within the application. It implements a feedback reporting mechanism using PostHog, allowing users to submit their feedback through a modal interface in both desktop and mobile views.

Detailed summary

  • Added reportProductFeedback function in report.ts to capture user feedback.
  • Integrated feedback submission in SecondaryNav component with a feedback dropdown.
  • Implemented feedback collection in MobileBurgerMenuButton with a toggleable section.
  • Added success notifications upon feedback submission using toast.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Replaced external Feedback link with an in-app feedback panel in the header and mobile menu.
    • Panel includes a textarea (max 1000 chars), Cancel and Submit actions; Submit is disabled when empty, shows a success message, clears input and closes the panel.
    • Adds an in-panel “Contact support” link for technical issues and preserves existing header controls.
  • Style

    • Expandable/collapsible feedback UI with visual indicators and improved mobile menu scrolling and positioning.

@GiselleNessi GiselleNessi self-assigned this Aug 21, 2025
@GiselleNessi GiselleNessi requested review from a team as code owners August 21, 2025 15:00
Copy link

changeset-bot bot commented Aug 21, 2025

⚠️ No Changeset found

Latest commit: 0e0e7d6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

vercel bot commented Aug 21, 2025

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

Project Deployment Preview Comments Updated (UTC)
docs-v2 Ready Ready Preview Comment Aug 22, 2025 5:15pm
thirdweb-www Ready Ready Preview Comment Aug 22, 2025 5:15pm
3 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
nebula Skipped Skipped Aug 22, 2025 5:15pm
thirdweb_playground Skipped Skipped Aug 22, 2025 5:15pm
wallet-ui Skipped Skipped Aug 22, 2025 5:15pm

Copy link
Contributor

coderabbitai bot commented Aug 21, 2025

Walkthrough

Replaces external Feedback links with in-app feedback UIs in the desktop secondary nav and mobile burger menu: adds client-side state, toggleable panels containing a textarea, Cancel/Submit handlers, an internal "Contact support" NavLink, and calls a new analytics reporter; Submit shows a success toast, clears input, and closes the panel.

Changes

Cohort / File(s) Summary
Secondary nav feedback dropdown
apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
Added client-side state (showFeedbackDropdown, modalFeedback) and handlers (handleModalSubmit, handleModalCancel); replaced external Feedback link with an in-page dropdown dialog (textarea, Cancel/Submit); invokes reportProductFeedback with { feedback, feedbackLength, source: "desktop" }; shows success toast; added NavLink to /team/~/support; positioned absolutely with z-index and accessibility attributes.
Mobile menu feedback section
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
Introduced collapsible feedback section (showFeedbackSection, modalFeedback) with Chevron toggle, textarea (maxLength 1000), Cancel/Submit handlers; replaced external Feedback navigation with in-menu interactive panel; invokes reportProductFeedback with { feedback, feedbackLength, source: "mobile" }; shows success toast, clears input, hides section; added overflow-y-auto for drawer.
Analytics reporter
apps/dashboard/src/@/analytics/report.ts
Added exported function `reportProductFeedback(properties: { feedback: string; feedbackLength: number; source: "desktop"

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Nav/Menu UI
  participant State as Local State
  participant Handler as Submit/Cancel Handler
  participant Analytics as reportProductFeedback
  participant Toast as sonner.toast

  User->>UI: Open Feedback panel
  UI->>State: set showFeedback = true
  UI->>User: Render textarea + actions

  User->>UI: Type feedback
  UI->>State: update modalFeedback

  alt Submit
    User->>UI: Click Submit
    UI->>Handler: invoke handleModalSubmit
    Handler->>Analytics: reportProductFeedback({feedback, feedbackLength, source})
    Analytics-->>Handler: ack
    Handler->>Toast: show success toast
    Handler->>State: clear modalFeedback
    Handler->>State: set showFeedback = false
    UI->>User: Hide panel
  else Cancel
    User->>UI: Click Cancel
    UI->>Handler: invoke handleModalCancel
    Handler->>State: clear modalFeedback
    Handler->>State: set showFeedback = false
    UI->>User: Hide panel
  end

  User->>UI: Click "Contact support"
  UI->>UI: Navigate to /team/~/support
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch gi/product-feedback-top-menu

🪧 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 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.

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Aug 21, 2025
Copy link
Contributor

graphite-app bot commented Aug 21, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

Copy link

codecov bot commented Aug 21, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.53%. Comparing base (6caba38) to head (0e0e7d6).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7895   +/-   ##
=======================================
  Coverage   56.53%   56.53%           
=======================================
  Files         904      904           
  Lines       58592    58592           
  Branches     4143     4143           
=======================================
  Hits        33126    33126           
  Misses      25360    25360           
  Partials      106      106           
Flag Coverage Δ
packages 56.53% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

github-actions bot commented Aug 21, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.06 KB (0%) 1.3 s (0%) 275 ms (+241.21% 🔺) 1.6 s
thirdweb (cjs) 357.05 KB (0%) 7.2 s (0%) 761 ms (+21.34% 🔺) 8 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 73 ms (+1084.35% 🔺) 188 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 66 ms (+4076.5% 🔺) 76 ms
thirdweb/react (minimal + tree-shaking) 19.15 KB (0%) 383 ms (0%) 100 ms (+656.23% 🔺) 483 ms

Copy link
Contributor

@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: 6

🧹 Nitpick comments (5)
apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx (2)

64-72: Add accessibility attributes and use functional state toggle on the trigger.

Expose expanded state, wire it to the popup, and prefer functional updates.

Apply this diff:

-        <button
-          type="button"
-          onClick={() => setShowFeedbackDropdown(!showFeedbackDropdown)}
-          className="text-muted-foreground text-sm hover:text-foreground"
-        >
+        <button
+          type="button"
+          aria-expanded={showFeedbackDropdown}
+          aria-controls="feedback-dropdown"
+          onClick={() => setShowFeedbackDropdown((v) => !v)}
+          className="text-muted-foreground text-sm hover:text-foreground"
+        >

73-117: Reduce duplication by extracting a shared FeedbackPanel.

This panel is largely duplicated in MobileBurgerMenuButton. Extracting a small client component improves consistency and maintenance.

Example shape (new file):

// apps/dashboard/src/app/(app)/components/feedback/FeedbackPanel.client.tsx
"use client";
import React from "react";
import Link from "next/link";

type FeedbackPanelProps = {
  value: string;
  onChange: (v: string) => void;
  onCancel: () => void;
  onSubmit: (e?: React.FormEvent) => void;
  id?: string;
};

export function FeedbackPanel({
  value,
  onChange,
  onCancel,
  onSubmit,
  id = "feedback",
}: FeedbackPanelProps): React.ReactElement {
  const isEmpty = !value.trim();
  return (
    <form onSubmit={onSubmit} aria-labelledby={`${id}-heading`} className="space-y-4">
      <h2 id={`${id}-heading`} className="text-foreground text-base font-sans">
        Share your feedback with us:
      </h2>
      <label htmlFor={`${id}-text`} className="sr-only">
        Feedback
      </label>
      <textarea
        id={`${id}-text`}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        maxLength={1000}
        aria-describedby={`${id}-help`}
        className="w-full bg-background text-foreground rounded-lg p-4 min-h-[120px] resize-none border border-border placeholder-muted-foreground font-sans text-sm"
        placeholder="Tell us what you think..."
      />
      <div className="flex items-start justify-between gap-4">
        <div className="text-muted-foreground text-xs font-sans">
          <div>Have a technical issue?</div>
          <div>
            <Link id={`${id}-help`} href="/team/~/~/support" className="underline hover:text-foreground transition-colors">
              Contact support
            </Link>
            .
          </div>
        </div>
        <div className="flex gap-3 flex-shrink-0">
          <button type="button" onClick={onCancel} className="bg-transparent text-foreground px-4 py-1.5 rounded-full font-sans text-sm border border-border hover:bg-muted">
            Cancel
          </button>
          <button type="submit" disabled={isEmpty} aria-disabled={isEmpty} className="bg-primary text-primary-foreground px-4 py-1.5 rounded-full font-sans text-sm hover:bg-primary/90 disabled:opacity-50">
            Submit
          </button>
        </div>
      </div>
    </form>
  );
}
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (3)

41-43: State additions are fine, but consider extracting to a small hook.

You can centralize feedback state/handlers across desktop and mobile (e.g., useFeedbackPanel).


210-221: A11y: reflect expanded state and use functional toggling.

Expose the expanded state and associate the control with the collapsible region.

Apply this diff:

-                <button
-                  type="button"
-                  className="flex items-center justify-between text-muted-foreground hover:text-foreground"
-                  onClick={() => setShowFeedbackSection(!showFeedbackSection)}
-                >
+                <button
+                  type="button"
+                  aria-expanded={showFeedbackSection}
+                  aria-controls="mobile-feedback-section"
+                  className="flex items-center justify-between text-muted-foreground hover:text-foreground"
+                  onClick={() => setShowFeedbackSection((v) => !v)}
+                >

62-72: Restore original body overflow instead of hardcoding “initial”.

This avoids clobbering a pre-existing body overflow style when multiple overlays are used.

Example:

useLayoutEffect(() => {
  const prev = document.body.style.overflow;
  document.body.style.overflow = isMenuOpen ? "hidden" : prev;
  return () => {
    document.body.style.overflow = prev;
  };
}, [isMenuOpen]);
📜 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 2d12249 and 1c8a9c6.

📒 Files selected for processing (2)
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
🧠 Learnings (12)
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
PR: thirdweb-dev/js#7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.client.tsx : Client components must start with `'use client';` before imports.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-06-17T18:30:52.976Z
Learnt from: MananTank
PR: thirdweb-dev/js#7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Use React Query (`tanstack/react-query`) for all client data fetching.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
⏰ 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). (7)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx (2)

1-1: Correct: client component directive is present.

This component uses React state, so having "use client" is required and correct.


5-5: Importing useState is appropriate here.

No concerns with this addition.

apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (2)

4-6: Icon imports for expand/collapse LGTM.

These are appropriate for the new collapsible section.


89-89: Good: make drawer scrollable.

Adding overflow-y-auto to the drawer fixes content clipping on smaller screens.

@vercel vercel bot temporarily deployed to Preview – nebula August 21, 2025 18:23 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 21, 2025 18:23 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 21, 2025 18:23 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 21, 2025 18:23 Inactive
@GiselleNessi GiselleNessi added the DO NOT MERGE This pull request is still in progress and is not ready to be merged. label Aug 21, 2025
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 21, 2025 18:33 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 21, 2025 18:33 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 21, 2025 18:33 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula August 21, 2025 18:33 Inactive
Copy link
Contributor

@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: 0

♻️ Duplicate comments (2)
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (2)

265-279: Use design-system Button primitives for actions (consistency + a11y).

Replace raw buttons with <Button> and keep disabled semantics; aligns with apps/dashboard UI guidelines.

-                          <button
-                            type="button"
-                            onClick={handleModalCancel}
-                            className="flex-1 bg-transparent text-foreground px-3 py-2 rounded-full font-sans text-sm border border-border hover:bg-muted transition-colors"
-                          >
-                            Cancel
-                          </button>
-                          <button
-                            type="submit"
-                            disabled={!modalFeedback.trim()}
-                            aria-disabled={!modalFeedback.trim()}
-                            className="flex-1 bg-primary text-primary-foreground px-3 py-2 rounded-full font-sans text-sm hover:bg-primary/90 transition-colors disabled:opacity-50"
-                          >
-                            Submit
-                          </button>
+                          <Button
+                            type="button"
+                            onClick={handleModalCancel}
+                            variant="outline"
+                            className="flex-1"
+                          >
+                            Cancel
+                          </Button>
+                          <Button
+                            type="submit"
+                            disabled={!modalFeedback.trim()}
+                            aria-disabled={!modalFeedback.trim()}
+                            className="flex-1 disabled:opacity-50"
+                          >
+                            Submit
+                          </Button>

256-263: Fix the hard-coded support link to use the team slug from the router

The “Contact support” link currently points to /team/~/support, which will 404 unless you literally have a team named “~”. It needs to read the team_slug from useParams() and build the correct path, falling back to the team overview at /team if no slug is present.

• Add the useParams import alongside the existing imports.
• Inside your MobileBurgerMenuButton component (near the other hooks), derive the slug and compute supportHref.
• Swap the hard-coded href on the NavLink to use this new variable.

Relevant diff:

--- a/apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
+++ b/apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
@@ 3,6 ✎
 import Link from "next/link";
+import { useParams } from "next/navigation";

@@ function MobileBurgerMenuButton() {
   "use client";

   // …other hooks…
+  const { team_slug } = useParams<{ team_slug?: string }>() ?? {};
+  const supportHref = team_slug ? `/team/${team_slug}/~/support` : "/team";

   // …JSX…
@@ 258,263 ✎
-  <NavLink
-    href="/team/~/support"
+  <NavLink
+    href={supportHref}
     className="underline hover:text-foreground transition-colors"
   >
     Contact support

With these changes, the link will correctly resolve for the current team or redirect to /team when no slug is available.

🧹 Nitpick comments (6)
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (6)

42-43: State is scoped and minimal, but consider a clearer name.

Nit: modalFeedback reads like a modal; this UI is an in-panel section. Consider feedbackText to reduce confusion.

-  const [modalFeedback, setModalFeedback] = useState("");
+  const [feedbackText, setFeedbackText] = useState("");

Note: update corresponding references in handlers and JSX.


52-52: Narrow the event type for better DX.

Type the form event precisely.

-  const handleModalSubmit = (e?: React.FormEvent) => {
+  const handleModalSubmit = (e?: React.FormEvent<HTMLFormElement>) => {

214-226: Toggler: add a11y attributes and use functional state update.

  • Add aria-expanded and aria-controls for screen readers.
  • Use functional update to avoid stale closures.
-                <button
+                <button
                   type="button"
-                  className="flex items-center justify-between text-muted-foreground hover:text-foreground"
-                  onClick={() => setShowFeedbackSection(!showFeedbackSection)}
+                  className="flex items-center justify-between text-muted-foreground hover:text-foreground"
+                  aria-expanded={showFeedbackSection}
+                  aria-controls="mobile-feedback-section"
+                  onClick={() => setShowFeedbackSection((v) => !v)}
                 >
                   <span>Feedback</span>

228-236: Wrap the feedback block with region semantics for better navigation.

Give the container an id (to match aria-controls) and landmark semantics.

-                {showFeedbackSection && (
-                  <div className="pl-0 pr-4 space-y-4 mb-6">
+                {showFeedbackSection && (
+                  <div
+                    id="mobile-feedback-section"
+                    role="region"
+                    aria-labelledby="mobile-feedback-heading"
+                    className="pl-0 pr-4 space-y-4 mb-6"
+                  >
                     <h3
                       id="mobile-feedback-heading"
                       className="text-sm font-medium text-foreground mb-2"
                     >
                       Share your feedback with us:
                     </h3>

241-248: Textarea: add basic form semantics.

Add name and required to play nicely with forms and validation.

-                      <textarea
+                      <textarea
                         id="mobile-feedback-text"
-                        value={modalFeedback}
-                        onChange={(e) => setModalFeedback(e.target.value)}
+                        name="feedback"
+                        required
+                        value={modalFeedback}
+                        onChange={(e) => setModalFeedback(e.target.value)}
                         maxLength={1000}
                         aria-describedby="mobile-feedback-help"
                         className="w-full bg-background text-foreground rounded-lg p-3 min-h-[100px] resize-none border border-border focus:border-border focus:outline-none placeholder-muted-foreground font-sans text-sm"
                         placeholder="Tell us what you think..."
                       />

214-285: Optional: auto-focus the textarea when opening the feedback section.

Improves UX on mobile; focus only when the panel transitions open.

Add outside the shown range:

import { useEffect, useRef } from "react";

// inside component
const feedbackRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
  if (showFeedbackSection) {
    feedbackRef.current?.focus();
  }
}, [showFeedbackSection]);

And attach to the textarea:

-  <textarea
+  <textarea
+    ref={feedbackRef}
📜 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 04e750c and 5da4e3b.

📒 Files selected for processing (2)
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
🧠 Learnings (7)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
PR: thirdweb-dev/js#7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
⏰ 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). (8)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (5)

4-6: LGTM: Chevron icons wired for the collapsible feedback control.

Imports are minimal and tree-shake clean.


19-19: Good move: adopt NavLink for internal navigation (support link).

This aligns with dashboard navigation guidelines; consider standardizing other internal Links in a follow-up.


52-60: No PII + form-safe submit — nice.

Preventing default and logging only length in non-prod addresses the earlier privacy concern.


62-65: Clear cancel behavior.

Resets input and closes the section without side effects.


94-94: Scrollable drawer container is the right call.

Adding overflow-y-auto prevents viewport lock on long content.

@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 22, 2025 16:46 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula August 22, 2025 16:46 Inactive
Copy link
Contributor

@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: 3

♻️ Duplicate comments (1)
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (1)

261-273: Ensure the support link includes the current team_slug

The <NavLink> is currently hard-coded to "/team/~/support", but your routing setup defines a literal ~ segment after a dynamic [team_slug]. You need to pull in the active team_slug via useParams() and interpolate it into the href.

– File: apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
– Lines: ~261–273

Suggested changes:

+ import { useParams } from "next/navigation";
  // …inside your component body…
+ const { team_slug } = useParams() as { team_slug: string };

   <div className="flex flex-col gap-3">
     <p
       id="mobile-feedback-help"
       className="text-muted-foreground text-xs"
     >
       Have a technical issue?{" "}
-      <NavLink
-        href="/team/~/support"
+      <NavLink
+        href={`/team/${team_slug}/~/support`}
         className="underline hover:text-foreground transition-colors"
       >
         Contact support
       </NavLink>
       .
  • Import and invoke useParams() from next/navigation to retrieve the dynamic team_slug.
  • Interpolate both the slug and the literal ~ segment into your path.
🧹 Nitpick comments (8)
apps/dashboard/src/@/analytics/report.ts (1)

565-575: Pass the properties object unchanged to posthog.capture for consistency.

Across this file we typically forward a single typed properties object directly. After the privacy refactor above, keep forwarding a single object to align with our analytics style guide.

-  posthog.capture("product feedback submitted", {
-    feedbackLength,
-    source: properties.source,
-  });
+  posthog.capture("product feedback submitted", { feedbackLength, source: properties.source });
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (4)

226-237: Improve a11y on the Feedback toggle.

Expose state to AT and link the control to the content region.

-                <button
+                <button
                   type="button"
                   className="flex items-center justify-between text-muted-foreground hover:text-foreground"
-                  onClick={() => setShowFeedbackSection(!showFeedbackSection)}
+                  onClick={() => setShowFeedbackSection(!showFeedbackSection)}
+                  aria-expanded={showFeedbackSection}
+                  aria-controls="mobile-feedback-section"
                 >

And add id="mobile-feedback-section" on the container (see next comment).


239-295: Wrap the feedback area with landmark semantics and a stable id; use Button primitives for actions.

  • Add region semantics + id for aria-controls target.
  • Replace raw buttons with our design-system Button components per dashboard guidelines.
-                {showFeedbackSection && (
-                  <div className="pl-0 pr-4 space-y-4 mb-6">
+                {showFeedbackSection && (
+                  <div
+                    id="mobile-feedback-section"
+                    role="region"
+                    aria-labelledby="mobile-feedback-heading"
+                    className="pl-0 pr-4 space-y-4 mb-6"
+                  >
@@
-                        <div className="flex gap-3">
-                          <button
-                            type="button"
-                            onClick={handleModalCancel}
-                            className="flex-1 bg-transparent text-foreground px-3 py-2 rounded-full font-sans text-sm border border-border hover:bg-muted transition-colors"
-                          >
-                            Cancel
-                          </button>
-                          <button
-                            type="submit"
-                            disabled={!modalFeedback.trim()}
-                            aria-disabled={!modalFeedback.trim()}
-                            className="flex-1 bg-primary text-primary-foreground px-3 py-2 rounded-full font-sans text-sm hover:bg-primary/90 transition-colors disabled:opacity-50"
-                          >
-                            Submit
-                          </button>
-                        </div>
+                        <div className="flex gap-3">
+                          <Button
+                            type="button"
+                            onClick={handleModalCancel}
+                            variant="outline"
+                            className="flex-1"
+                          >
+                            Cancel
+                          </Button>
+                          <Button
+                            type="submit"
+                            disabled={!modalFeedback.trim()}
+                            aria-disabled={!modalFeedback.trim()}
+                            className="flex-1 disabled:opacity-50"
+                          >
+                            Submit
+                          </Button>
+                        </div>

Note: Button is already imported at line 21.


78-88: Prefer useEffect over useLayoutEffect for scroll locking.

No layout measurements here; useEffect avoids unnecessary sync blocking.

-import { useLayoutEffect, useState } from "react";
+import { useEffect, useState } from "react";
@@
-  useLayoutEffect(() => {
+  useEffect(() => {

136-152: Use NavLink for internal routes to align with dashboard navigation patterns.

Swap internal Links to NavLink: /account, /chainlist, /explore, /home. Keep external links (Docs, Playground) as is.

-                <Link
+                <NavLink
                   className="flex items-center gap-2 py-1 text-base text-muted-foreground hover:text-foreground"
                   href="/account"
                 >
@@
-                </Link>
+                </NavLink>
@@
-            <Link
+            <NavLink
               className="text-muted-foreground hover:text-foreground "
               href="/chainlist"
             >
               Chainlist
-            </Link>
+            </NavLink>
@@
-            <Link
+            <NavLink
               className="text-muted-foreground hover:text-foreground "
               href="/explore"
             >
               Explore Contracts
-            </Link>
+            </NavLink>
@@
-            <Link
+            <NavLink
               className="text-base text-muted-foreground hover:text-foreground"
               href="/home"
             >
               Home Page
-            </Link>
+            </NavLink>

Imports already include NavLink (line 21).

Also applies to: 183-189, 199-205, 206-212

apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx (3)

80-87: Add a11y state and dialog semantics.

  • Reflect expanded state on the toggle and connect it to the dialog with aria-controls.
  • Mark the popup as a modal dialog (role + aria-modal).
-        <button
+        <button
           type="button"
           onClick={() => setShowFeedbackDropdown(!showFeedbackDropdown)}
           className="text-muted-foreground text-sm hover:text-foreground border border-border px-3 py-1.5 rounded-full hover:bg-muted transition-colors"
+          aria-expanded={showFeedbackDropdown}
+          aria-controls="feedback-dropdown"
         >
@@
-          <div
+          <div
             id="feedback-dropdown"
-            role="dialog"
+            role="dialog"
+            aria-modal="true"
             aria-labelledby="feedback-heading"
             className="absolute top-full right-0 mt-2 bg-background border border-border rounded-2xl p-3 w-96 z-50"
           >

Also applies to: 89-101


130-145: Use Button primitives for actions (design system consistency).

Replace raw buttons with <Button> from @/components/ui/button.

+ import { Button } from "@/components/ui/button";
@@
-                  <button
-                    type="button"
-                    onClick={handleModalCancel}
-                    className="bg-transparent text-foreground px-4 py-1.5 rounded-full font-sans text-sm border border-border hover:bg-muted transition-colors"
-                  >
-                    Cancel
-                  </button>
-                  <button
-                    type="submit"
-                    disabled={!modalFeedback.trim()}
-                    aria-disabled={!modalFeedback.trim()}
-                    className="bg-primary text-primary-foreground px-4 py-1.5 rounded-full font-sans text-sm hover:bg-primary/90 transition-colors disabled:opacity-50"
-                  >
-                    Submit
-                  </button>
+                  <Button type="button" onClick={handleModalCancel} variant="outline">
+                    Cancel
+                  </Button>
+                  <Button type="submit" disabled={!modalFeedback.trim()} aria-disabled={!modalFeedback.trim()} className="disabled:opacity-50">
+                    Submit
+                  </Button>

120-128: Minor: ensure help text is associated with the textarea.

You already set aria-describedby="feedback-help" on the textarea; move id="feedback-help" to the wrapping text block (not the NavLink only) to guarantee association if the link gets focus.

-                <div className="text-muted-foreground text-xs font-sans">
+                <div id="feedback-help" className="text-muted-foreground text-xs font-sans">
📜 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 5da4e3b and 8b2716d.

📒 Files selected for processing (3)
  • apps/dashboard/src/@/analytics/report.ts (1 hunks)
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (6 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
🧠 Learnings (18)
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/@/analytics/report.ts : Review `src/@/analytics/report.ts` before adding analytics events to check for duplicates

Applied to files:

  • apps/dashboard/src/@/analytics/report.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/@/analytics/report.ts : Analytics event name: human-readable `<subject> <verb>` (e.g., "contract deployed"); function: `report<Subject><Verb>` (PascalCase)

Applied to files:

  • apps/dashboard/src/@/analytics/report.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/src/@/analytics/report.ts : Mandatory JSDoc: explain Why the event exists and Who owns it (`username`).

Applied to files:

  • apps/dashboard/src/@/analytics/report.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/src/@/analytics/report.ts : Typed properties: accept a single `properties` object and pass it unchanged to `posthog.capture`.

Applied to files:

  • apps/dashboard/src/@/analytics/report.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/src/@/analytics/report.ts : Reporting helper: `report<Subject><Verb>` (PascalCase); all live in `src/@/analytics/report.ts`.

Applied to files:

  • apps/dashboard/src/@/analytics/report.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.client.tsx : Client components must start with `'use client';` before imports.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
PR: thirdweb-dev/js#7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Pages requiring fast transitions where data is prefetched on the client.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Use React Query (`tanstack/react-query`) for all client data fetching.

Applied to files:

  • apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
🧬 Code graph analysis (2)
apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx (1)
apps/dashboard/src/@/analytics/report.ts (1)
  • reportProductFeedback (565-575)
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx (1)
apps/dashboard/src/@/analytics/report.ts (1)
  • reportProductFeedback (565-575)
⏰ 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). (8)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Build Packages
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/@/analytics/report.ts (1)

555-564: Verify analytics event naming, uniqueness, and ownership

  • The event name "product feedback submitted" correctly follows the <subject> <verb> pattern, and the function reportProductFeedback matches the PascalCase requirement.
  • A search in apps/dashboard/src/@/analytics/report.ts shows this is the only occurrence of both the event name and its reporting function, so there are no duplicates.
  • Please confirm that @gisellechacon is the intended owner of this event (the PR author is @GiselleNessi).

Comment on lines +555 to +575
/**
* ### Why do we need to report this event?
* - To track user feedback and sentiment about the product
* - To identify common issues or feature requests
* - To measure user satisfaction and engagement
* - To prioritize product improvements based on user input
*
* ### Who is responsible for this event?
* @gisellechacon
*/
export function reportProductFeedback(properties: {
feedback: string;
feedbackLength: number;
source: "desktop" | "mobile";
}) {
posthog.capture("product feedback submitted", {
feedback: properties.feedback,
feedbackLength: properties.feedbackLength,
source: properties.source,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Do not send raw free‑text feedback to PostHog (PII/secret leakage risk).

Freeform feedback can contain emails, wallet addresses, API keys, etc. We should never ship raw text to analytics. Capture only metadata (e.g., length, source) and route the text to a first‑party backend (support inbox or DB) if needed.

Apply this diff to keep analytics privacy‑safe (capture only length + source), and compute length inside the reporter so callers don’t need to:

-export function reportProductFeedback(properties: {
-  feedback: string;
-  feedbackLength: number;
-  source: "desktop" | "mobile";
-}) {
-  posthog.capture("product feedback submitted", {
-    feedback: properties.feedback,
-    feedbackLength: properties.feedbackLength,
-    source: properties.source,
-  });
-}
+export function reportProductFeedback(properties: {
+  feedback: string;
+  source: "desktop" | "mobile";
+}) {
+  // Intentionally avoid sending the raw feedback to analytics.
+  const feedbackLength = properties.feedback.trim().length;
+  posthog.capture("product feedback submitted", {
+    feedbackLength,
+    source: properties.source,
+  });
+}

Follow-ups (separate PR ok):

  • Create an internal API route (e.g., POST /api/feedback) to persist the text to a first‑party store if product needs the content. Do not proxy via PostHog. I can draft this if helpful.
📝 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
/**
* ### Why do we need to report this event?
* - To track user feedback and sentiment about the product
* - To identify common issues or feature requests
* - To measure user satisfaction and engagement
* - To prioritize product improvements based on user input
*
* ### Who is responsible for this event?
* @gisellechacon
*/
export function reportProductFeedback(properties: {
feedback: string;
feedbackLength: number;
source: "desktop" | "mobile";
}) {
posthog.capture("product feedback submitted", {
feedback: properties.feedback,
feedbackLength: properties.feedbackLength,
source: properties.source,
});
}
export function reportProductFeedback(properties: {
feedback: string;
source: "desktop" | "mobile";
}) {
// Intentionally avoid sending the raw feedback to analytics.
const feedbackLength = properties.feedback.trim().length;
posthog.capture("product feedback submitted", {
feedbackLength,
source: properties.source,
});
}
🤖 Prompt for AI Agents
In apps/dashboard/src/@/analytics/report.ts around lines 555 to 575, the
reporter currently sends raw free‑text feedback to PostHog which risks leaking
PII; change it so the function computes feedback length internally and only
sends metadata (feedbackLength and source) to posthog.capture, removing the raw
feedback field from the payload; keep the function signature accepting the
feedback string (callers can still pass it) but do not include the text in
analytics — persist full text to a first‑party backend via a separate API route
in a follow‑up PR instead.

Comment on lines +43 to +52
const handleModalSubmit = (e?: React.FormEvent) => {
e?.preventDefault();

// Report feedback to PostHog
reportProductFeedback({
feedback: modalFeedback,
feedbackLength: modalFeedback.trim().length,
source: "desktop",
});

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid sending free‑text feedback to analytics; let the reporter derive metadata.

Update the call to the privacy‑safe reporter that does not forward the text to PostHog.

-    reportProductFeedback({
-      feedback: modalFeedback,
-      feedbackLength: modalFeedback.trim().length,
-      source: "desktop",
-    });
+    reportProductFeedback({
+      feedback: modalFeedback,
+      source: "desktop",
+    });

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
around lines 43 to 52, the code currently sends free-text user feedback to
PostHog via reportProductFeedback; change the call to use the privacy-safe
reporter (or the same function without the feedback text) so only metadata is
sent. Remove the feedback/modalFeedback field from the payload and send only
non‑identifying fields such as feedbackLength: modalFeedback.trim().length,
source: "desktop", and any derived category/sentiment fields (compute locally if
needed) or call the dedicated privacy-safe helper (e.g.,
reportProductFeedbackMetadata) instead so the raw text is never forwarded to
analytics.

Comment on lines +54 to +71
const handleModalSubmit = (e?: React.FormEvent) => {
e?.preventDefault();

// Report feedback to PostHog
reportProductFeedback({
feedback: modalFeedback,
feedbackLength: modalFeedback.trim().length,
source: "mobile",
});

// Show success notification
toast.success("Feedback submitted successfully!", {
description: "Thank you for your feedback. We'll review it shortly.",
});

setModalFeedback("");
setShowFeedbackSection(false);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Don’t forward raw feedback to analytics; rely on reporter to derive length.

Call the reporter with the text and let it compute metadata, but ensure the reporter never forwards the text to PostHog (see report.ts fix).

Apply:

-    reportProductFeedback({
-      feedback: modalFeedback,
-      feedbackLength: modalFeedback.trim().length,
-      source: "mobile",
-    });
+    reportProductFeedback({
+      feedback: modalFeedback,
+      source: "mobile",
+    });
📝 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
const handleModalSubmit = (e?: React.FormEvent) => {
e?.preventDefault();
// Report feedback to PostHog
reportProductFeedback({
feedback: modalFeedback,
feedbackLength: modalFeedback.trim().length,
source: "mobile",
});
// Show success notification
toast.success("Feedback submitted successfully!", {
description: "Thank you for your feedback. We'll review it shortly.",
});
setModalFeedback("");
setShowFeedbackSection(false);
};
const handleModalSubmit = (e?: React.FormEvent) => {
e?.preventDefault();
// Report feedback to PostHog
reportProductFeedback({
feedback: modalFeedback,
source: "mobile",
});
// Show success notification
toast.success("Feedback submitted successfully!", {
description: "Thank you for your feedback. We'll review it shortly.",
});
setModalFeedback("");
setShowFeedbackSection(false);
};
🤖 Prompt for AI Agents
In apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx around
lines 54 to 71, the call to reportProductFeedback is currently passing raw
feedback plus derived metadata; update it to only pass the feedback text (e.g.,
reportProductFeedback({ feedback: modalFeedback })) and remove feedbackLength
and source arguments so the reporter derives metadata internally and is
responsible for not forwarding the raw text to PostHog; keep the toast and
state-reset logic unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Dashboard Involves changes to the Dashboard. DO NOT MERGE This pull request is still in progress and is not ready to be merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant