Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@elie222 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 40 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughAdds a per-account setup flow: new client SetupContent UI, SetupProgressCard, API route /api/user/setup-progress, a useSetupProgress SWR hook, NavUser dropdown, SideNav adjustments (TopNav removed), and a small Early Access UI addition. Page-level setup logic moved into SetupContent; TopNav deleted and its dropdown migrated into NavUser. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant SideNav as SideNav / SetupProgressCard
participant SetupContent as SetupContent
participant Hook as useSetupProgress (SWR)
participant API as GET /api/user/setup-progress
participant DB as Prisma
participant Cookie as ReplyZeroCookie
User->>SideNav: Open app
SideNav->>Hook: subscribe "/api/user/setup-progress"
SetupContent->>Hook: subscribe "/api/user/setup-progress"
Hook->>API: fetch
API->>DB: query EmailAccount + related rows
API->>Cookie: read reply-zero onboarding cookie
API-->>Hook: { steps, completed, total, isComplete }
Hook-->>SideNav: data
Hook-->>SetupContent: data
alt isComplete
SideNav-->>User: hide progress card
SetupContent-->>User: show FeatureGrid
else not complete
SideNav-->>User: show progress card
SetupContent-->>User: show Checklist
end
sequenceDiagram
actor User
participant Nav as NavUser
participant Theme as next-themes
participant Router as Next Router
participant AuthAPI as logOut()
User->>Nav: Click avatar
Nav-->>User: show dropdown
User->>Nav: Toggle theme
Nav->>Theme: setTheme(...)
User->>Nav: Select item (Usage/Mail/Settings)
Nav->>Router: push(account-scoped path)
User->>Nav: Sign out
Nav->>AuthAPI: logOut(origin)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 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
Status, Documentation and Community
|
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (5)
apps/web/components/SetupProgressCard.tsx (2)
49-55: Guard against divide-by-zero and add an accessible title to the SVG.
- If total were ever 0, percentage becomes NaN; add a guard.
- Our a11y rules require a <title> for SVGs; include the current percentage.
Apply this diff:
- const percentage = (completed / total) * 100; + const safeTotal = total > 0 ? total : 1; + const percentage = Math.max(0, Math.min(100, (completed / safeTotal) * 100)); @@ - <svg className="h-8 w-8 -rotate-90 transform" width="32" height="32"> + <svg + className="h-8 w-8 -rotate-90 transform" + width="32" + height="32" + role="img" + aria-label={`Setup progress: ${Math.round(percentage)}%`} + > + <title>{`Setup progress: ${Math.round(percentage)}%`}</title>Also applies to: 58-59
10-16: Optional: Use LoadingContent for consistency with app-wide loading patterns.Returning null while loading is fine here, but if you want a consistent skeleton/placeholder experience, wrap the card with LoadingContent and pass loading={isLoading}.
apps/web/app/api/user/setup-progress/route.ts (1)
34-36: Avoid throwing a plain Error for not-found; rely on middleware or return a typed 404.withEmailAccount typically ensures a valid account context. If this check is truly reachable, consider returning a 404 JSON with a generic message rather than throwing a raw Error, which can lead to noisy logs and inconsistent error shapes.
Apply this diff if you prefer to rely on the middleware guarantee:
- if (!emailAccount) { - throw new Error("Email account not found"); - } + // withEmailAccount should guarantee a valid emailAccountId in request.auth. + // If this is ever falsy, returning a consistent empty state is safer than throwing. + if (!emailAccount) { + return { + steps: { aiAssistant: false, bulkUnsubscribe: false, replyTracker: false }, + completed: 0, + total: 3, + isComplete: false, + }; + }Alternative: Move the check to the GET handler and
return NextResponse.json({ error: "Not found" }, { status: 404 })for a typed error response.apps/web/app/(app)/[emailAccountId]/setup/page.tsx (1)
5-9: Fix Next.js params typing: don’t typeparamsas a Promise orawaititIn the App Router,
paramsis a plain object. Typing it as a Promise and awaiting it is unnecessary and incorrect under strict TypeScript settings.Apply this diff:
-export default async function SetupPage(props: { - params: Promise<{ emailAccountId: string }>; -}) { - const { emailAccountId } = await props.params; +export default async function SetupPage({ + params, +}: { + params: { emailAccountId: string }; +}) { + const { emailAccountId } = params;apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx (1)
185-191: Add ARIA to the progress bar for accessibilityExpose progress semantics to assistive tech.
Apply this diff:
<div className="h-2 w-32 overflow-hidden rounded-full bg-muted"> <div - className="h-2 rounded-full bg-primary" - style={{ width: `${progressPercentage}%` }} + className="h-2 rounded-full bg-primary" + style={{ width: `${progressPercentage}%` }} + role="progressbar" + aria-label="Setup progress" + aria-valuemin={0} + aria-valuemax={100} + aria-valuenow={Math.round(progressPercentage)} /> </div>
📜 Review details
Configuration used: .coderabbit.yaml
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 (7)
apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx(1 hunks)apps/web/app/(app)/[emailAccountId]/setup/page.tsx(1 hunks)apps/web/app/api/user/setup-progress/route.ts(1 hunks)apps/web/components/SetupProgressCard.tsx(1 hunks)apps/web/components/SideNav.tsx(2 hunks)apps/web/hooks/useSetupProgress.ts(1 hunks)version.txt(1 hunks)
🧰 Additional context used
📓 Path-based instructions (23)
!{.cursor/rules/*.mdc}
📄 CodeRabbit Inference Engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
version.txtapps/web/components/SideNav.tsxapps/web/hooks/useSetupProgress.tsapps/web/app/api/user/setup-progress/route.tsapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
version.txtapps/web/components/SideNav.tsxapps/web/hooks/useSetupProgress.tsapps/web/app/api/user/setup-progress/route.tsapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx
apps/web/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/components/SideNav.tsxapps/web/hooks/useSetupProgress.tsapps/web/app/api/user/setup-progress/route.tsapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx
apps/web/**/*.tsx
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/components/SideNav.tsxapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx
apps/web/components/**/*.tsx
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
Use React Hook Form with Zod validation for form handling
Use the
LoadingContentcomponent to handle loading and error states consistently in data-fetching components.Use PascalCase for components (e.g.
components/Button.tsx)
Files:
apps/web/components/SideNav.tsxapps/web/components/SetupProgressCard.tsx
**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/components/SideNav.tsxapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
Don't export imported variables.
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions.
Don't use parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/components/SideNav.tsxapps/web/hooks/useSetupProgress.tsapps/web/app/api/user/setup-progress/route.tsapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/components/SideNav.tsxapps/web/hooks/useSetupProgress.tsapps/web/app/api/user/setup-progress/route.tsapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx
**/*.{jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
Don't use the return value of React.render.
Make sure all dependencies are correctly specified in React hooks.
Make sure all React hooks are called from the top level of component functions.
Don't use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/components/SideNav.tsxapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
Make sure all anchors are valid and navigable.
Ensure all ARIA properties (aria-*) are valid.
Use valid, non-abstract ARIA roles for elements with ARIA roles.
Use valid ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/components/SideNav.tsxapps/web/components/SetupProgressCard.tsxapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsxapps/web/hooks/**/*.ts
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
Use SWR for efficient data fetching and caching
apps/web/hooks/**/*.ts: Use SWR for client-side data fetching and caching.
Callmutate()after successful mutations to refresh SWR data on the client.Files:
apps/web/hooks/useSetupProgress.tsapps/web/hooks/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
Call
mutate()after successful mutations to refresh dataFiles:
apps/web/hooks/useSetupProgress.ts**/*.ts
📄 CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)
**/*.ts: The same validation should be done in the server action too
Define validation schemas using ZodFiles:
apps/web/hooks/useSetupProgress.tsapps/web/app/api/user/setup-progress/route.tsapps/web/hooks/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/hooks.mdc)
Place custom hooks in the
apps/web/hooks/directory.Files:
apps/web/hooks/useSetupProgress.tsapps/web/hooks/use*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/hooks.mdc)
apps/web/hooks/use*.{js,jsx,ts,tsx}: Name custom hooks with theuseprefix (e.g.,useAccounts.ts).
For fetching data from API endpoints in custom hooks, prefer usinguseSWR.
Create dedicated hooks for specific data types (e.g.,useAccounts,useLabels).
Custom hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions.
Keep custom hooks focused on a single responsibility.Files:
apps/web/hooks/useSetupProgress.tsapps/web/app/**
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/api/user/setup-progress/route.tsapps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsxapps/web/app/api/**/route.ts
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
apps/web/app/api/**/route.ts: UsewithAuthfor user-level operations
UsewithEmailAccountfor email-account-level operations
Do NOT use POST API routes for mutations - use server actions instead
No need for try/catch in GET routes when using middleware
Export response types from GET routes
apps/web/app/api/**/route.ts: Wrap all GET API route handlers withwithAuthorwithEmailAccountmiddleware for authentication and authorization.
Export response types from GET API routes for type-safe client usage.
Do not use try/catch in GET API routes when using authentication middleware; rely on centralized error handling.Files:
apps/web/app/api/user/setup-progress/route.ts**/api/**/route.ts
📄 CodeRabbit Inference Engine (.cursor/rules/security.mdc)
**/api/**/route.ts: ALL API routes that handle user data MUST use appropriate authentication and authorization middleware (withAuth or withEmailAccount).
ALL database queries in API routes MUST be scoped to the authenticated user/account (e.g., include userId or emailAccountId in query filters).
Always validate that resources belong to the authenticated user before performing operations (resource ownership validation).
UsewithEmailAccountmiddleware for API routes that operate on a specific email account (i.e., use or requireemailAccountId).
UsewithAuthmiddleware for API routes that operate at the user level (i.e., use or require onlyuserId).
UsewithErrormiddleware (with proper validation) for public endpoints, custom authentication, or cron endpoints.
Cron endpoints MUST usewithErrormiddleware and validate the cron secret usinghasCronSecret(request)orhasPostCronSecret(request).
Cron endpoints MUST capture unauthorized attempts withcaptureExceptionand return a 401 status for unauthorized requests.
All parameters in API routes MUST be validated for type, format, and length before use.
Request bodies in API routes MUST be validated using Zod schemas before use.
All Prisma queries in API routes MUST only return necessary fields and never expose sensitive data.
Error messages in API routes MUST not leak internal information or sensitive data; use generic error messages and SafeError where appropriate.
API routes MUST use a consistent error response format, returning JSON with an error message and status code.
AllfindUniqueandfindFirstPrisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).
AllfindManyPrisma calls in API routes MUST be scoped to the authenticated user's data.
Never use direct object references in API routes without ownership checks (prevent IDOR vulnerabilities).
Prevent mass assignment vulnerabilities by only allowing explicitly whitelisted fields in update operations in AP...Files:
apps/web/app/api/user/setup-progress/route.tsapps/web/app/api/**/*.{ts,js}
📄 CodeRabbit Inference Engine (.cursor/rules/security-audit.mdc)
apps/web/app/api/**/*.{ts,js}: All API route handlers in 'apps/web/app/api/' must use authentication middleware: withAuth, withEmailAccount, or withError (with custom authentication logic).
All Prisma queries in API routes must include user/account filtering (e.g., emailAccountId or userId in WHERE clauses) to prevent unauthorized data access.
All parameters used in API routes must be validated before use; do not use parameters from 'params' or request bodies directly in queries without validation.
Request bodies in API routes should use Zod schemas for validation.
API routes should only return necessary fields using Prisma's 'select' and must not include sensitive data in error messages.
Error messages in API routes must not reveal internal details; use generic errors and SafeError for user-facing errors.
All QStash endpoints (API routes called via publishToQstash or publishToQstashQueue) must use verifySignatureAppRouter to verify request authenticity.
All cron endpoints in API routes must use hasCronSecret or hasPostCronSecret for authentication.
Do not hardcode weak or plaintext secrets in API route files; secrets must not be directly assigned as string literals.
Review all new withError usage in API routes to ensure custom authentication is implemented where required.Files:
apps/web/app/api/user/setup-progress/route.tsapps/web/app/(app)/*/**
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsxapps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsxapps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsxapps/web/app/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirectiveFiles:
apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx🧠 Learnings (18)
📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/hooks/**/*.ts : Use SWR for client-side data fetching and caching.Applied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:04:30.467Z
Learnt from: CR PR: elie222/inbox-zero#0 File: apps/web/CLAUDE.md:0-0 Timestamp: 2025-07-18T15:04:30.467Z Learning: Applies to apps/web/hooks/**/*.ts : Use SWR for efficient data fetching and cachingApplied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:05:41.705Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/hooks.mdc:0-0 Timestamp: 2025-07-18T15:05:41.705Z Learning: Applies to apps/web/hooks/use*.{js,jsx,ts,tsx} : For fetching data from API endpoints in custom hooks, prefer using `useSWR`.Applied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:05:41.705Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/hooks.mdc:0-0 Timestamp: 2025-07-18T15:05:41.705Z Learning: Applies to apps/web/hooks/use*.{js,jsx,ts,tsx} : Create dedicated hooks for specific data types (e.g., `useAccounts`, `useLabels`).Applied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:05:41.705Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/hooks.mdc:0-0 Timestamp: 2025-07-18T15:05:41.705Z Learning: Applies to apps/web/hooks/use*.{js,jsx,ts,tsx} : Custom hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions.Applied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:05:41.705Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/hooks.mdc:0-0 Timestamp: 2025-07-18T15:05:41.705Z Learning: Applies to apps/web/hooks/use*.{js,jsx,ts,tsx} : Name custom hooks with the `use` prefix (e.g., `useAccounts.ts`).Applied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:05:56.644Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/index.mdc:0-0 Timestamp: 2025-07-18T15:05:56.644Z Learning: Fetching data from the API using SWRApplied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-19T17:50:22.078Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/ui-components.mdc:0-0 Timestamp: 2025-07-19T17:50:22.078Z Learning: Applies to {components,app}/**/*.tsx : For API get requests to server use the `swr` packageApplied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:04:44.818Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/data-fetching.mdc:0-0 Timestamp: 2025-07-18T15:04:44.818Z Learning: Applies to {app,components}/**/*.{ts,tsx} : For API GET requests to server, use the `swr` packageApplied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-20T09:00:16.505Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/project-structure.mdc:0-0 Timestamp: 2025-07-20T09:00:16.505Z Learning: Use `swr` for data fetching in deeply nested componentsApplied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:07:00.269Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/page-structure.mdc:0-0 Timestamp: 2025-07-18T15:07:00.269Z Learning: Applies to apps/web/app/(app)/*/**/**/*.tsx : If we're in a deeply nested component we will use swr to fetch via APIApplied to files:
apps/web/hooks/useSetupProgress.ts📚 Learning: 2025-07-18T15:04:30.467Z
Learnt from: CR PR: elie222/inbox-zero#0 File: apps/web/CLAUDE.md:0-0 Timestamp: 2025-07-18T15:04:30.467Z Learning: Applies to apps/web/app/api/**/route.ts : Use `withEmailAccount` for email-account-level operationsApplied to files:
apps/web/app/api/user/setup-progress/route.ts📚 Learning: 2025-07-18T15:05:26.713Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/get-api-route.mdc:0-0 Timestamp: 2025-07-18T15:05:26.713Z Learning: Applies to app/api/**/route.ts : Always wrap the handler with `withAuth` or `withEmailAccount` for consistent error handling and authentication in GET API routes.Applied to files:
apps/web/app/api/user/setup-progress/route.ts📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/app/api/**/route.ts : Wrap all GET API route handlers with `withAuth` or `withEmailAccount` middleware for authentication and authorization.Applied to files:
apps/web/app/api/user/setup-progress/route.ts📚 Learning: 2025-07-18T15:05:16.146Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/fullstack-workflow.mdc:0-0 Timestamp: 2025-07-18T15:05:16.146Z Learning: Applies to apps/web/app/api/**/route.ts : Export response types from GET API routes for type-safe client usage.Applied to files:
apps/web/app/api/user/setup-progress/route.ts📚 Learning: 2025-07-18T17:27:46.389Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/security.mdc:0-0 Timestamp: 2025-07-18T17:27:46.389Z Learning: Applies to **/api/**/route.ts : Use `withEmailAccount` middleware for API routes that operate on a specific email account (i.e., use or require `emailAccountId`).Applied to files:
apps/web/app/api/user/setup-progress/route.ts📚 Learning: 2025-07-18T15:05:26.713Z
Learnt from: CR PR: elie222/inbox-zero#0 File: .cursor/rules/get-api-route.mdc:0-0 Timestamp: 2025-07-18T15:05:26.713Z Learning: Applies to app/api/**/route.ts : Do not use try/catch in GET API route handlers, as `withAuth` and `withEmailAccount` handle error catching.Applied to files:
apps/web/app/api/user/setup-progress/route.ts📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222 PR: elie222/inbox-zero#537 File: apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx:30-34 Timestamp: 2025-07-08T13:14:07.449Z Learning: The clean onboarding page in apps/web/app/(app)/[emailAccountId]/clean/onboarding/page.tsx is intentionally Gmail-specific and should show an error for non-Google email accounts rather than attempting to support multiple providers.Applied to files:
apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsxapps/web/app/(app)/[emailAccountId]/setup/page.tsx🧬 Code Graph Analysis (6)
apps/web/components/SideNav.tsx (1)
apps/web/components/SetupProgressCard.tsx (1)
SetupProgressCard(10-40)apps/web/hooks/useSetupProgress.ts (1)
apps/web/app/api/user/setup-progress/route.ts (1)
GetSetupProgressResponse(7-9)apps/web/app/api/user/setup-progress/route.ts (2)
apps/web/utils/middleware.ts (1)
withEmailAccount(251-255)apps/web/utils/cookies.ts (1)
REPLY_ZERO_ONBOARDING_COOKIE(2-2)apps/web/components/SetupProgressCard.tsx (3)
apps/web/providers/EmailAccountProvider.tsx (1)
useAccount(72-82)apps/web/hooks/useSetupProgress.ts (1)
useSetupProgress(4-6)apps/web/utils/path.ts (1)
prefixPath(1-4)apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx (5)
apps/web/utils/path.ts (1)
prefixPath(1-4)apps/web/components/ui/card.tsx (1)
Card(138-138)apps/web/hooks/useSetupProgress.ts (1)
useSetupProgress(4-6)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-27)apps/web/components/Typography.tsx (2)
PageHeading(110-110)SectionDescription(114-114)apps/web/app/(app)/[emailAccountId]/setup/page.tsx (2)
apps/web/utils/email-account.ts (1)
checkUserOwnsEmailAccount(5-19)apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx (1)
SetupContent(231-249)⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (9)
version.txt (1)
1-1: Version bump looks good.No issues with the patch version increment.
apps/web/components/SideNav.tsx (1)
45-45: Nice, minimal integration of SetupProgressCard into the left sidebar.Import and conditional render are scoped to the left sidebar state, keeping the UI lean. Placement above SidebarGroupContent feels right for visibility without being intrusive.
Also applies to: 216-217
apps/web/hooks/useSetupProgress.ts (1)
1-6: Global SWR fetcher is configured correctly
Confirmed that you have an<SWRConfig>with afetcher: enhancedFetcherinapps/web/providers/SWRProvider.tsx(around lines 130–134). No further changes needed for this hook.apps/web/app/api/user/setup-progress/route.ts (2)
11-16: Correct use of withEmailAccount and typed response.
- Handler is properly wrapped with withEmailAccount.
- Response type is exported for client usage.
- No try/catch clutter; middleware should handle errors.
38-46: Confirm that cookie-based replyTracker is the intended source of truth.Using a client cookie to mark setup completion is simple but not per-account and not durable across devices/browsers. If reply-tracking configuration is persisted server-side, prefer that instead.
Would you like me to propose a small schema addition (e.g., accountPreferences.replyTrackerConfigured boolean) and the corresponding update to the route and UI?
apps/web/app/(app)/[emailAccountId]/setup/page.tsx (1)
13-14: LGTM: Delegation to SetupContent keeps the page thinGood move delegating logic/UI to
SetupContentand keeping auth/ownership checks server-side here. This aligns with the app router’s best practices.apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx (3)
18-48: LGTM: FeatureCard is clean, typed, and uses prefixPath correctlyGood separation of concerns and consistent shadcn/tailwind usage. Passing
hrefviaprefixPathensures per-account scoping.
50-85: All per-account routes verified
Confirmed that the following paths exist under apps/web/app/(app)/[emailAccountId]/:
/automation/bulk-unsubscribe/reply-zero/cold-email-blocker/assistant/onboardingNo changes required.
231-236: Refine useSetupProgress to isolate SWR cache per accountThe API route is already scoped by account via
withEmailAccount(it pullsemailAccountIdfromrequest.auth), so no backend changes are necessary. We only need to ensure the client‐side hook key incorporates the activeemailAccountIdto prevent SWR from reusing stale data across accounts.• In apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx:
-export function SetupContent({ emailAccountId }: { emailAccountId: string }) { - const { data, isLoading, error } = useSetupProgress(); +export function SetupContent({ emailAccountId }: { emailAccountId: string }) { + const { data, isLoading, error } = useSetupProgress(emailAccountId);• In apps/web/hooks/useSetupProgress.ts:
-export function useSetupProgress() { - return useSWR<GetSetupProgressResponse>("/api/user/setup-progress"); -} +export function useSetupProgress(emailAccountId: string) { + // Include the account in the SWR key so each account’s data caches separately + const key = `/api/user/setup-progress?account=${encodeURIComponent(emailAccountId)}`; + return useSWR<GetSetupProgressResponse>(key); +}Or, if your global fetcher supports array keys:
export function useSetupProgress(emailAccountId: string) { return useSWR<GetSetupProgressResponse>( ["/api/user/setup-progress", emailAccountId], fetcher ); }No changes to the API route are required—
withEmailAccountalready enforces and supplies the correctemailAccountId.Likely an incorrect or invalid review comment.
| totalSteps: number; | ||
| isSetupComplete: boolean; | ||
| }) { | ||
| const progressPercentage = (completedCount / totalSteps) * 100; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Guard and clamp progress percentage to avoid Infinity/NaN and overflow
If totalSteps is 0, width becomes Infinity%. Also clamp to [0, 100] to avoid visual overflow on miscounts.
Apply this diff:
- const progressPercentage = (completedCount / totalSteps) * 100;
+ const rawProgress = totalSteps > 0 ? (completedCount / totalSteps) * 100 : 0;
+ const progressPercentage = Math.min(100, Math.max(0, rawProgress));📝 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 progressPercentage = (completedCount / totalSteps) * 100; | |
| const rawProgress = totalSteps > 0 ? (completedCount / totalSteps) * 100 : 0; | |
| const progressPercentage = Math.min(100, Math.max(0, rawProgress)); |
🤖 Prompt for AI Agents
In apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx around line 268,
the progressPercentage calculation can produce Infinity or NaN when totalSteps
is 0 or produce values outside 0–100; guard against divide-by-zero and clamp the
result by computing progressPercentage as 0 when totalSteps is falsy (or use
completedCount/totalSteps only if totalSteps>0) then apply Math.min(100,
Math.max(0, computedValue)) so the final percentage is always a finite number
between 0 and 100.
| const { data, isLoading } = useSetupProgress(); | ||
|
|
||
| if (isLoading || !data || data.isComplete) { | ||
| return null; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Pass account id to the hook to align with per-account caching.
Once the hook keys by account id, feed it here to avoid cross-account cache collisions.
Apply this diff:
- const { data, isLoading } = useSetupProgress();
+ const { data, isLoading } = useSetupProgress(emailAccountId);📝 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 { data, isLoading } = useSetupProgress(); | |
| if (isLoading || !data || data.isComplete) { | |
| return null; | |
| const { data, isLoading } = useSetupProgress(emailAccountId); | |
| if (isLoading || !data || data.isComplete) { | |
| return null; |
🤖 Prompt for AI Agents
In apps/web/components/SetupProgressCard.tsx around lines 12–15 the
useSetupProgress hook is called without an account id which risks cross-account
cache collisions; retrieve the current account id (from this component's props
or the app's account context/hook such as useCurrentAccount/useAccount) and call
useSetupProgress(accountId) instead, and handle the case where accountId is
undefined (return null or loading) so the hook only keys by a specific account.
| import useSWR from "swr"; | ||
| import type { GetSetupProgressResponse } from "@/app/api/user/setup-progress/route"; | ||
|
|
||
| export function useSetupProgress() { | ||
| return useSWR<GetSetupProgressResponse>("/api/user/setup-progress"); | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Update all useSetupProgress() call sites to pass account id.
After keying by accountId, ensure callers pass it to avoid duplicating caches under "unknown".
Use this to find and review call sites:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Call sites of useSetupProgress:"
rg -n -C3 --type=ts --type=tsx '\buseSetupProgress\s*\('
echo
echo "Suggested edit pattern: useSetupProgress(emailAccountId)"Length of output: 179
I’ll broaden the search to include both .ts and .tsx files without relying on built-in type filters.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching call sites of useSetupProgress in .ts and .tsx files:"
rg -n -C3 '\buseSetupProgress\s*\(' --glob '*.ts' --glob '*.tsx'Length of output: 1831
Pass emailAccountId into every useSetupProgress call
After keying the SWR cache by account ID, update all call sites to pass the emailAccountId argument so you don’t end up with entries under “unknown”:
• apps/web/components/SetupProgressCard.tsx
• apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
--- a/apps/web/components/SetupProgressCard.tsx
+++ b/apps/web/components/SetupProgressCard.tsx
@@ -11,7 +11,7 @@ export function SetupProgressCard() {
const { emailAccountId } = useAccount();
- const { data, isLoading } = useSetupProgress();
+ const { data, isLoading } = useSetupProgress(emailAccountId);
--- a/apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
+++ b/apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
@@ -229,7 +229,7 @@ export function SetupContent({ emailAccountId }: { emailAccountId: string }) {
- const { data, isLoading, error } = useSetupProgress();
+ const { data, isLoading, error } = useSetupProgress(emailAccountId);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/web/hooks/useSetupProgress.ts around lines 1-6, the hook currently uses
a static key and must accept an emailAccountId to key SWR properly; change the
function signature to accept (emailAccountId: string | undefined) and pass that
into useSWR as part of the key (e.g.
`/api/user/setup-progress?emailAccountId=${emailAccountId}` or an array key),
then update all call sites (apps/web/components/SetupProgressCard.tsx and
apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx) to pass the
emailAccountId value when calling useSetupProgress so cache entries are not
stored under "unknown".
| export function useSetupProgress() { | ||
| return useSWR<GetSetupProgressResponse>("/api/user/setup-progress"); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Prevent cross-account SWR cache bleed by keying on emailAccountId.
Right now the SWR key is a static string. If a user switches accounts in the same session, the cached data can display the wrong progress until revalidation. Key the cache by accountId to segregate caches.
Apply this diff:
-export function useSetupProgress() {
- return useSWR<GetSetupProgressResponse>("/api/user/setup-progress");
-}
+export function useSetupProgress(accountId?: string) {
+ // Include accountId in the SWR key to avoid cache collisions when switching accounts.
+ return useSWR<GetSetupProgressResponse>([
+ "/api/user/setup-progress",
+ accountId ?? "unknown",
+ ]);
+}Follow-up: Update call sites to pass the current account id.
📝 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.
| export function useSetupProgress() { | |
| return useSWR<GetSetupProgressResponse>("/api/user/setup-progress"); | |
| } | |
| export function useSetupProgress(accountId?: string) { | |
| // Include accountId in the SWR key to avoid cache collisions when switching accounts. | |
| return useSWR<GetSetupProgressResponse>([ | |
| "/api/user/setup-progress", | |
| accountId ?? "unknown", | |
| ]); | |
| } |
🤖 Prompt for AI Agents
In apps/web/hooks/useSetupProgress.ts around lines 4 to 6, the SWR key is a
static string which allows cache bleed across accounts; change the hook to
accept an emailAccountId (or accountId) parameter and use a compound SWR key
that includes that id (e.g.
`/api/user/setup-progress?accountId=${emailAccountId}` or an array key
["/api/user/setup-progress", emailAccountId]) so caches are segregated per
account; then update all call sites to pass the current account id when invoking
the hook so each account has its own SWR cache entry.
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/web/components/SideNavWithTopNav.tsx (1)
10-16: Consider renaming this component/fileTopNav is gone; consider renaming SideNavWithTopNav to reflect current responsibility (e.g., SideNavLayout) to reduce future confusion.
📜 Review details
Configuration used: .coderabbit.yaml
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 (5)
apps/web/app/(app)/early-access/page.tsx(1 hunks)apps/web/components/NavUser.tsx(1 hunks)apps/web/components/SideNav.tsx(4 hunks)apps/web/components/SideNavWithTopNav.tsx(2 hunks)apps/web/components/TopNav.tsx(0 hunks)
💤 Files with no reviewable changes (1)
- apps/web/components/TopNav.tsx
🧰 Additional context used
📓 Path-based instructions (16)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
apps/web/**/*.tsx
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
apps/web/components/**/*.tsx
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
Use React Hook Form with Zod validation for form handling
Use the
LoadingContentcomponent to handle loading and error states consistently in data-fetching components.Use PascalCase for components (e.g.
components/Button.tsx)
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
!{.cursor/rules/*.mdc}
📄 CodeRabbit Inference Engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
Don't export imported variables.
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions.
Don't use parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
**/*.{jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
Don't use the return value of React.render.
Make sure all dependencies are correctly specified in React hooks.
Make sure all React hooks are called from the top level of component functions.
Don't use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
Make sure all anchors are valid and navigable.
Ensure all ARIA properties (aria-*) are valid.
Use valid, non-abstract ARIA roles for elements with ARIA roles.
Use valid ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/components/NavUser.tsxapps/web/app/(app)/early-access/page.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/components/SideNav.tsxapps/web/app/**
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/early-access/page.tsxapps/web/app/(app)/*/page.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
apps/web/app/(app)/*/page.tsx: Create new pages at: apps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directly
apps/web/app/(app)/*/page.tsx: Create new pages at:apps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components for direct data loadingFiles:
apps/web/app/(app)/early-access/page.tsxapps/web/app/(app)/*/**
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
Components for the page are either put in page.tsx, or in the apps/web/app/(app)/PAGE_NAME folder
Files:
apps/web/app/(app)/early-access/page.tsxapps/web/app/(app)/*/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
If you need to use onClick in a component, that component is a client component and file must start with 'use client'
Files:
apps/web/app/(app)/early-access/page.tsxapps/web/app/(app)/*/**/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/page-structure.mdc)
If we're in a deeply nested component we will use swr to fetch via API
Files:
apps/web/app/(app)/early-access/page.tsxapps/web/app/**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)
Components with
onClickmust be client components withuse clientdirectiveFiles:
apps/web/app/(app)/early-access/page.tsx🧬 Code Graph Analysis (4)
apps/web/components/NavUser.tsx (5)
apps/web/providers/EmailAccountProvider.tsx (1)
useAccount(72-82)apps/web/components/ProfileImage.tsx (1)
ProfileImage(3-18)apps/web/utils/path.ts (1)
prefixPath(1-4)apps/web/utils/email/provider-types.ts (1)
isGoogleProvider(1-3)apps/web/utils/user.ts (1)
logOut(5-16)apps/web/app/(app)/early-access/page.tsx (2)
apps/web/components/ui/card.tsx (5)
Card(138-138)CardHeader(139-139)CardTitle(141-141)CardDescription(142-142)CardContent(143-143)apps/web/components/Button.tsx (1)
Button(60-87)apps/web/components/SideNavWithTopNav.tsx (1)
apps/web/components/ui/sidebar.tsx (1)
SidebarInset(807-807)apps/web/components/SideNav.tsx (4)
apps/web/components/ui/sidebar.tsx (3)
SidebarTrigger(820-820)SidebarHeader(805-805)SidebarContent(799-799)apps/web/components/AccountSwitcher.tsx (1)
AccountSwitcher(26-32)apps/web/components/SetupProgressCard.tsx (1)
SetupProgressCard(10-40)apps/web/components/NavUser.tsx (1)
NavUser(33-155)🔇 Additional comments (9)
apps/web/app/(app)/early-access/page.tsx (2)
18-31: Sender Categories card addition looks goodUI structure follows shadcn Card/Header/Content patterns and Button asChild with Next Link is correct. Nice placement after EarlyAccessFeatures.
28-29: Global/smart-categoriesRoute Exists and Redirects to Account-Scoped Path
The application defines a global/smart-categoriesroute in
apps/web/app/(app)/(redirects)/smart-categories/page.tsxwhich immediately redirects users into their account-scoped path viaredirectToEmailAccountPath. Linking directly to/smart-categoriesfrom the early-access page is therefore correct—no changes needed.apps/web/components/SideNavWithTopNav.tsx (3)
6-6: Import cleanup aligns with TopNav removalDropping SidebarTrigger from this file and only using SidebarInset/SidebarProvider is consistent with the new sidebar UX.
32-32: Padding change is sensible after removing TopNavAdding pt-9 on SidebarInset provides breathing room where TopNav used to be.
21-25: No update needed for setup routeThe
SideNavWithTopNavwrapper lives under the(app)layout, and the setup pages (/[emailAccountId]/setup) are meant to display the sidebar (including the setup progress card). Only the onboarding flow at/[emailAccountId]/onboardingshould hide the nav, so the existing conditional is correct.apps/web/components/SideNav.tsx (3)
44-47: New imports are appropriate and usedSidebarTrigger, SetupProgressCard, and NavUser are correctly imported and used in this module.
Also applies to: 58-58
223-224: Setup progress in sidebar content is well placedConditionally rendering SetupProgressCard only when expanded avoids clutter in icon mode and matches UX expectations.
244-245: NavUser in footer integrates the user menu into the sidebarThis aligns with removing TopNav. Nice placement in SidebarFooter after the referral and links.
apps/web/components/NavUser.tsx (1)
1-156: Solid account-aware user dropdown
- Auth-aware rendering is correct (Sign in button vs dropdown).
- Theme toggle with onSelect + preventDefault is good.
- Account-scoped links via prefixPath are consistent.
- Sign-out flows through logOut is fine for client components.
No blockers from my side.
| <Link href="/setup"> | ||
| <div className="flex items-center rounded-md p-3 text-foreground"> | ||
| <div className="flex items-center rounded-md p-3 text-foreground justify-between"> | ||
| <Logo className="h-3.5" /> | ||
| <SidebarTrigger name="left-sidebar" /> | ||
| </div> | ||
| </Link> | ||
| ) : null} | ||
| ) : ( | ||
| <div className="pb-2"> | ||
| <SidebarTrigger name="left-sidebar" /> | ||
| </div> | ||
| )} |
There was a problem hiding this comment.
Fix nested interactive elements and account-scoped setup link
Two issues here:
- SidebarTrigger is nested inside a Link, creating an invalid interactive-in-interactive pattern and causing clicks on the trigger to also navigate to /setup.
- The /setup link is not account-prefixed; elsewhere setup is per-account via prefixPath.
Refactor to separate the trigger from the link and use an account-scoped href.
Apply this diff:
- {state.includes("left-sidebar") ? (
- <Link href="/setup">
- <div className="flex items-center rounded-md p-3 text-foreground justify-between">
- <Logo className="h-3.5" />
- <SidebarTrigger name="left-sidebar" />
- </div>
- </Link>
- ) : (
+ {state.includes("left-sidebar") ? (
+ <div className="flex items-center rounded-md p-3 text-foreground justify-between">
+ <Link href={prefixPath(emailAccountId, "/setup")} className="flex items-center">
+ <Logo className="h-3.5" />
+ </Link>
+ <SidebarTrigger name="left-sidebar" />
+ </div>
+ ) : (
<div className="pb-2">
<SidebarTrigger name="left-sidebar" />
</div>
)}Additionally, ensure emailAccountId is available in this component:
// Inside SideNav component body (near other hooks)
const { emailAccountId } = useAccount();🤖 Prompt for AI Agents
In apps/web/components/SideNav.tsx around lines 208 to 218, remove the nested
interactive element by not rendering SidebarTrigger inside the Link; instead
render the Link (account-prefixed) separately and render SidebarTrigger outside
of it so clicks on the trigger do not navigate. Replace the hardcoded "/setup"
href with the account-scoped path using prefixPath/emailAccountId (e.g. build
the href via prefixPath(`/account/${emailAccountId}/setup`) or the project’s
existing prefix helper) and ensure emailAccountId is available by adding const {
emailAccountId } = useAccount() in the SideNav component body near the other
hooks.
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/web/components/SideNav.tsx (1)
193-203: Fix nested interactive elements and account-scope the setup linkSidebarTrigger is currently nested inside a Link, which is invalid and causes unintended navigation. Also, setup should be account-scoped.
Apply this diff to separate the trigger from the link and prefix the path:
- {state.includes("left-sidebar") ? ( - <Link href="/setup"> - <div className="flex items-center rounded-md p-3 text-foreground justify-between"> - <Logo className="h-3.5" /> - <SidebarTrigger name="left-sidebar" /> - </div> - </Link> - ) : ( - <div className="pb-2"> - <SidebarTrigger name="left-sidebar" /> - </div> - )} + {state.includes("left-sidebar") ? ( + <div className="flex items-center rounded-md p-3 text-foreground justify-between"> + <Link href={prefixPath(emailAccountId, "/setup")} className="flex items-center"> + <Logo className="h-3.5" /> + </Link> + <SidebarTrigger name="left-sidebar" /> + </div> + ) : ( + <div className="pb-2"> + <SidebarTrigger name="left-sidebar" /> + </div> + )}Additionally, ensure emailAccountId is available in this component:
// Inside SideNav component (near other hooks) const { emailAccountId } = useAccount();
🧹 Nitpick comments (4)
apps/web/components/NavUser.tsx (3)
159-168: Use resolvedTheme to handle "system" mode correctly when toggling themeUsing theme directly can mislabel/toggle incorrectly when the current mode is "system". Rely on resolvedTheme for both the label and the toggle logic.
Apply these diffs:
- const { theme, setTheme } = useTheme(); + const { theme, resolvedTheme, setTheme } = useTheme();- onSelect={(e) => { + onSelect={(e) => { e.preventDefault(); - setTheme(theme === "dark" ? "light" : "dark"); + const current = resolvedTheme ?? theme; + setTheme(current === "dark" ? "light" : "dark"); }} > <PaletteIcon className="mr-2 h-4 w-4" /> - {theme === "dark" ? "Light mode" : "Dark mode"} + {(resolvedTheme ?? theme) === "dark" ? "Light mode" : "Dark mode"}Also applies to: 39-40
110-115: Open external Help Center in a new tab and add rel for safetyFor an external link, open in a new tab and add rel="noopener noreferrer".
- <Link href="https://docs.getinboxzero.com"> + <Link href="https://docs.getinboxzero.com" target="_blank" rel="noopener noreferrer"> <BookIcon className="mr-2 h-4 w-4" /> Help Center </Link>
91-91: Guard against possibly null session.user.emailNextAuth can return null for email. Provide a safe fallback.
- <span className="truncate text-xs">{session.user.email}</span> + <span className="truncate text-xs"> + {session.user.email ?? emailAccount?.email ?? ""} + </span>apps/web/components/SideNav.tsx (1)
173-184: Make “Back” navigation account-scopedThe Back link should point to the account’s automation page.
- showMailNav - ? [ - { - name: "Back", - href: "/automation", - icon: ArrowLeftIcon, - }, - ] - : [], + showMailNav + ? [ + { + name: "Back", + href: prefixPath(emailAccountId, "/automation"), + icon: ArrowLeftIcon, + }, + ] + : [],Note: This assumes you add
const { emailAccountId } = useAccount();within the SideNav component body.
📜 Review details
Configuration used: .coderabbit.yaml
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/web/components/NavUser.tsx(1 hunks)apps/web/components/SideNav.tsx(5 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use@/for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier
Leverage TypeScript inference for better DX
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
apps/web/**/*.tsx
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data
Useresult?.serverErrorwithtoastErrorandtoastSuccess
UseLoadingContentcomponent to handle loading and error states consistently
Passloading,error, and children props toLoadingContent
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
apps/web/components/**/*.tsx
📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)
Use React Hook Form with Zod validation for form handling
Use the
LoadingContentcomponent to handle loading and error states consistently in data-fetching components.Use PascalCase for components (e.g.
components/Button.tsx)
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
!{.cursor/rules/*.mdc}
📄 CodeRabbit Inference Engine (.cursor/rules/cursor-rules.mdc)
Never place rule files in the project root, in subdirectories outside .cursor/rules, or in any other location
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)
**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)
**/*.{ts,tsx}: UsecreateScopedLoggerfor logging in backend TypeScript files
Typically add the logger initialization at the top of the file when usingcreateScopedLogger
Only use.with()on a logger instance within a specific function, not for a global loggerImport Prisma in the project using
import prisma from "@/utils/prisma";
**/*.{ts,tsx}: Don't use TypeScript enums.
Don't use TypeScript const enum.
Don't use the TypeScript directive @ts-ignore.
Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't use implicit any type on variable declarations.
Don't let variables evolve into any type through reassignments.
Don't use non-null assertions with the ! postfix operator.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use user-defined types.
Use as const instead of literal types and type annotations.
Use export type for types.
Use import type for types.
Don't declare empty interfaces.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Don't use TypeScript namespaces.
Don't export imported variables.
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions.
Don't use parameter properties in class constructors.
Use either T[] or Array consistently.
Initialize each enum member value explicitly.
Make sure all enum members are literal values.
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useelements in Next.js projects.
Don't use elements in Next.js projects.
Don't use namespace imports.
Don't access namespace imports dynamically.
Don't use global eval().
Don't use console.
Don't use debugger.
Don't use var.
Don't use with statements in non-strict contexts.
Don't use the arguments object.
Don't use consecutive spaces in regular expression literals.
Don't use the comma operator.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use useless this aliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names th...
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
!pages/_document.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
!pages/_document.{js,jsx,ts,tsx}: Don't import next/document outside of pages/_document.jsx in Next.js projects.
Don't import next/document outside of pages/_document.jsx in Next.js projects.
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
**/*.{jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't destructure props inside JSX components in Solid projects.
Don't use both children and dangerouslySetInnerHTML props on the same element.
Don't use Array index in keys.
Don't assign to React component props.
Don't define React components inside other components.
Don't use event handlers on non-interactive elements.
Don't assign JSX properties multiple times.
Don't add extra closing tags for components without children.
Use <>...</> instead of ....
Don't insert comments as text nodes.
Don't use the return value of React.render.
Make sure all dependencies are correctly specified in React hooks.
Make sure all React hooks are called from the top level of component functions.
Don't use unnecessary fragments.
Don't pass children as props.
Use semantic elements instead of role attributes in JSX.
Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx
**/*.{html,jsx,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)
**/*.{html,jsx,tsx}: Don't use or elements.
Don't use accessKey attribute on any HTML element.
Don't set aria-hidden="true" on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Only use the scope prop on elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assign tabIndex to non-interactive HTML elements.
Don't use positive integers for tabIndex property.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include a title element for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
Assign tabIndex to non-interactive HTML elements with aria-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include a type attribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden).
Always include a lang attribute on the html element.
Always include a title attribute for iframe elements.
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress.
Accompany onMouseOver/onMouseOut with onFocus/onBlur.
Include caption tracks for audio and video elements.
Make sure all anchors are valid and navigable.
Ensure all ARIA properties (aria-*) are valid.
Use valid, non-abstract ARIA roles for elements with ARIA roles.
Use valid ARIA state and property values.
Use valid values for the autocomplete attribute on input eleme...Files:
apps/web/components/NavUser.tsxapps/web/components/SideNav.tsx🧬 Code Graph Analysis (2)
apps/web/components/NavUser.tsx (5)
apps/web/providers/EmailAccountProvider.tsx (1)
useAccount(72-82)apps/web/components/ProfileImage.tsx (1)
ProfileImage(3-18)apps/web/utils/path.ts (1)
prefixPath(1-4)apps/web/utils/email/provider-types.ts (1)
isGoogleProvider(1-3)apps/web/utils/user.ts (1)
logOut(5-16)apps/web/components/SideNav.tsx (3)
apps/web/components/ui/sidebar.tsx (1)
SidebarTrigger(820-820)apps/web/components/SetupProgressCard.tsx (1)
SetupProgressCard(10-40)apps/web/components/NavUser.tsx (1)
NavUser(35-178)🔇 Additional comments (3)
apps/web/components/NavUser.tsx (1)
53-79: Overall structure of the menu looks solidGood use of DropdownMenu primitives, account-scoped links via prefixPath, and provider-gated items.
apps/web/components/SideNav.tsx (2)
207-209: SetupProgressCard placement LGTMConditionally rendering the setup card only when the left sidebar is present aligns with the updated layout and avoids clutter.
228-230: Footer integration of NavUser LGTMNavUser in the footer is a good fit and consolidates user controls in the sidebar per the new IA.
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Summary by CodeRabbit
New Features
UI
Refactor