-
Notifications
You must be signed in to change notification settings - Fork 574
feat: add feedback collection UI to navigation #7895
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughReplaces 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
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
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🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
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. |
Codecov Report✅ All modified and coverable lines are covered by tests. 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
🚀 New features to boost your workflow:
|
size-limit report 📦
|
There was a problem hiding this 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.
📒 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 localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
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
UseNavLink
for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()
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 withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()
to retrieve JWT from cookies on server side
UseAuthorization: Bearer
header – never embed tokens in URLs
Return typed results (e.g.,Project[]
,User[]
) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query
)
Use descriptive, stablequeryKeys
for React Query cache hits
ConfigurestaleTime
/cacheTime
in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-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.
apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/components/Header/SecondaryNav/SecondaryNav.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
Outdated
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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 routerThe “Contact support” link currently points to
/team/~/support
, which will 404 unless you literally have a team named “~”. It needs to read theteam_slug
fromuseParams()
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 yourMobileBurgerMenuButton
component (near the other hooks), derive the slug and computesupportHref
.
• Swap the hard-codedhref
on theNavLink
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 supportWith 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. ConsiderfeedbackText
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
andaria-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.
📒 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 localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
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
UseNavLink
for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()
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 withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()
to retrieve JWT from cookies on server side
UseAuthorization: Bearer
header – never embed tokens in URLs
Return typed results (e.g.,Project[]
,User[]
) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query
)
Use descriptive, stablequeryKeys
for React Query cache hits
ConfigurestaleTime
/cacheTime
in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-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.
There was a problem hiding this 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 currentteam_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 activeteam_slug
viauseParams()
and interpolate it into the href.– File:
apps/dashboard/src/app/(app)/components/MobileBurgerMenuButton.tsx
– Lines: ~261–273Suggested 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()
fromnext/navigation
to retrieve the dynamicteam_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 theproperties
object unchanged toposthog.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
: PreferuseEffect
overuseLayoutEffect
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; moveid="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.
📒 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 localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
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
UseNavLink
for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()
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 withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()
to retrieve JWT from cookies on server side
UseAuthorization: Bearer
header – never embed tokens in URLs
Return typed results (e.g.,Project[]
,User[]
) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query
)
Use descriptive, stablequeryKeys
for React Query cache hits
ConfigurestaleTime
/cacheTime
in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-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 functionreportProductFeedback
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
).
/** | ||
* ### 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, | ||
}); | ||
} |
There was a problem hiding this comment.
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.
/** | |
* ### 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.
const handleModalSubmit = (e?: React.FormEvent) => { | ||
e?.preventDefault(); | ||
|
||
// Report feedback to PostHog | ||
reportProductFeedback({ | ||
feedback: modalFeedback, | ||
feedbackLength: modalFeedback.trim().length, | ||
source: "desktop", | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
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
reportProductFeedback
function inreport.ts
to capture user feedback.SecondaryNav
component with a feedback dropdown.MobileBurgerMenuButton
with a toggleable section.toast
.Summary by CodeRabbit
New Features
Style