Skip to content

Add setup card in nav#691

Merged
elie222 merged 8 commits intomainfrom
feat/setup-card
Aug 18, 2025
Merged

Add setup card in nav#691
elie222 merged 8 commits intomainfrom
feat/setup-card

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Aug 18, 2025

Summary by CodeRabbit

  • New Features

    • Per-account Inbox Zero setup flow with progress checklist and post-setup feature highlights.
    • Setup progress card in the sidebar linking to the account setup page.
    • New account user menu in the sidebar footer with account-scoped links, theme toggle, and sign out.
    • "Sender Categories" card with navigation on the Early Access page.
  • UI

    • Sidebar layout adjusted for a persistent trigger and added setup/user controls.
  • Refactor

    • Top navigation removed and its user/profile functionality moved into the sidebar.

@vercel
Copy link

vercel bot commented Aug 18, 2025

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

Project Deployment Preview Updated (UTC)
inbox-zero Ready Ready Preview Aug 18, 2025 7:12pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 18, 2025

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

📥 Commits

Reviewing files that changed from the base of the PR and between 185630c and 153af49.

📒 Files selected for processing (1)
  • version.txt (1 hunks)

Walkthrough

Adds 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

Cohort / File(s) Summary
Setup onboarding UI
apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx, apps/web/app/(app)/[emailAccountId]/setup/page.tsx
New client component SetupContent fetches setup progress and renders loading/error, checklist, or post-setup FeatureGrid. page.tsx simplified to a thin wrapper that now only passes emailAccountId to SetupContent.
Setup progress API & hook
apps/web/app/api/user/setup-progress/route.ts, apps/web/hooks/useSetupProgress.ts
Adds GET API route that computes steps (aiAssistant, bulkUnsubscribe, replyTracker) using Prisma and a reply-zero cookie; exports GetSetupProgressResponse. Adds useSetupProgress() SWR hook to consume the endpoint.
Setup progress surfacing
apps/web/components/SetupProgressCard.tsx, apps/web/components/SideNav.tsx
New SetupProgressCard component with circular SVG progress linking to account setup. SideNav updated to render the card in sidebar content, adjust SidebarTrigger placement, and include NavUser in footer.
User menu & top-nav rework
apps/web/components/NavUser.tsx, apps/web/components/SideNavWithTopNav.tsx, apps/web/components/TopNav.tsx
Adds NavUser client dropdown (account-aware, theme toggle, provider-conditional links). Removes TopNav file and its left-sidebar integration; SideNavWithTopNav layout adjusted (TopNav removed, added padding).
Early access UI
apps/web/app/(app)/early-access/page.tsx
Inserts a “Sender Categories” Card linking to /smart-categories.

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
Loading
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)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

A rabbit hops through code so neat,
Ticks three boxes with tiny feet.
API hums, SWR sings,
Sidebar blooms with progress rings.
TopNav hops away — new menus greet. 🥕🐇

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/setup-card

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

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

Other keywords and placeholders

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

Status, Documentation and Community

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

@claude
Copy link

claude bot commented Aug 18, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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 type params as a Promise or await it

In the App Router, params is 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 accessibility

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4f017b9 and 1e829bc.

📒 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.txt
  • apps/web/components/SideNav.tsx
  • apps/web/hooks/useSetupProgress.ts
  • apps/web/app/api/user/setup-progress/route.ts
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/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.txt
  • apps/web/components/SideNav.tsx
  • apps/web/hooks/useSetupProgress.ts
  • apps/web/app/api/user/setup-progress/route.ts
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/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.tsx
  • apps/web/hooks/useSetupProgress.ts
  • apps/web/app/api/user/setup-progress/route.ts
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/components/SideNav.tsx
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/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 LoadingContent component 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.tsx
  • apps/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.tsx
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/page.tsx
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.tsx
  • apps/web/hooks/useSetupProgress.ts
  • apps/web/app/api/user/setup-progress/route.ts
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/page.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use elements 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.tsx
  • apps/web/hooks/useSetupProgress.ts
  • apps/web/app/api/user/setup-progress/route.ts
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/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.tsx
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/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.tsx
  • apps/web/components/SetupProgressCard.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/page.tsx
apps/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.
Call mutate() after successful mutations to refresh SWR data on the client.

Files:

  • apps/web/hooks/useSetupProgress.ts
apps/web/hooks/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

Call mutate() after successful mutations to refresh data

Files:

  • 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 Zod

Files:

  • apps/web/hooks/useSetupProgress.ts
  • apps/web/app/api/user/setup-progress/route.ts
apps/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.ts
apps/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 the use prefix (e.g., useAccounts.ts).
For fetching data from API endpoints in custom hooks, prefer using useSWR.
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.ts
apps/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.ts
  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/page.tsx
apps/web/app/api/**/route.ts

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

apps/web/app/api/**/route.ts: Use withAuth for user-level operations
Use withEmailAccount for 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 with withAuth or withEmailAccount middleware 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).
Use withEmailAccount middleware for API routes that operate on a specific email account (i.e., use or require emailAccountId).
Use withAuth middleware for API routes that operate at the user level (i.e., use or require only userId).
Use withError middleware (with proper validation) for public endpoints, custom authentication, or cron endpoints.
Cron endpoints MUST use withError middleware and validate the cron secret using hasCronSecret(request) or hasPostCronSecret(request).
Cron endpoints MUST capture unauthorized attempts with captureException and 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.
All findUnique and findFirst Prisma calls in API routes MUST include ownership filters (e.g., userId or emailAccountId).
All findMany Prisma 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.ts
apps/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.ts
apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/page.tsx
apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/page.tsx
apps/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.tsx
  • apps/web/app/(app)/[emailAccountId]/setup/page.tsx
apps/web/app/**/*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)

Components with onClick must be client components with use client directive

Files:

  • apps/web/app/(app)/[emailAccountId]/setup/SetupContent.tsx
  • apps/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 caching

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} : 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 SWR

Applied 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` package

Applied 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` package

Applied 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 components

Applied 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 API

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/app/api/**/route.ts : Use `withEmailAccount` for email-account-level operations

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 : 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.tsx
  • apps/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 a fetcher: enhancedFetcher in apps/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 thin

Good move delegating logic/UI to SetupContent and 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 correctly

Good separation of concerns and consistent shadcn/tailwind usage. Passing href via prefixPath ensures 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/onboarding

No changes required.


231-236: Refine useSetupProgress to isolate SWR cache per account

The API route is already scoped by account via withEmailAccount (it pulls emailAccountId from request.auth), so no backend changes are necessary. We only need to ensure the client‐side hook key incorporates the active emailAccountId to 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—withEmailAccount already enforces and supplies the correct emailAccountId.

Likely an incorrect or invalid review comment.

totalSteps: number;
isSetupComplete: boolean;
}) {
const progressPercentage = (completedCount / totalSteps) * 100;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

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.

Suggested change
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.

Comment on lines +12 to +15
const { data, isLoading } = useSetupProgress();

if (isLoading || !data || data.isComplete) {
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

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.

Suggested change
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.

Comment on lines +1 to +6
import useSWR from "swr";
import type { GetSetupProgressResponse } from "@/app/api/user/setup-progress/route";

export function useSetupProgress() {
return useSWR<GetSetupProgressResponse>("/api/user/setup-progress");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 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".

Comment on lines +4 to +6
export function useSetupProgress() {
return useSWR<GetSetupProgressResponse>("/api/user/setup-progress");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

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.

Suggested change
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
Copy link

claude bot commented Aug 18, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

@claude
Copy link

claude bot commented Aug 18, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/web/components/SideNavWithTopNav.tsx (1)

10-16: Consider renaming this component/file

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1e829bc and 99c998b.

📒 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.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/components/NavUser.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/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 LoadingContent component 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.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/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.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/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.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/components/SideNav.tsx
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/components/SideNav.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use elements 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.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/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.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/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.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/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.tsx
  • apps/web/app/(app)/early-access/page.tsx
  • apps/web/components/SideNavWithTopNav.tsx
  • apps/web/components/SideNav.tsx
apps/web/app/**

📄 CodeRabbit Inference Engine (apps/web/CLAUDE.md)

NextJS app router structure with (app) directory

Files:

  • apps/web/app/(app)/early-access/page.tsx
apps/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 loading

Files:

  • apps/web/app/(app)/early-access/page.tsx
apps/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.tsx
apps/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.tsx
apps/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.tsx
apps/web/app/**/*.tsx

📄 CodeRabbit Inference Engine (.cursor/rules/project-structure.mdc)

Components with onClick must be client components with use client directive

Files:

  • 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 good

UI structure follows shadcn Card/Header/Content patterns and Button asChild with Next Link is correct. Nice placement after EarlyAccessFeatures.


28-29: Global /smart-categories Route Exists and Redirects to Account-Scoped Path
The application defines a global /smart-categories route in
apps/web/app/(app)/(redirects)/smart-categories/page.tsx which immediately redirects users into their account-scoped path via redirectToEmailAccountPath. Linking directly to /smart-categories from the early-access page is therefore correct—no changes needed.

apps/web/components/SideNavWithTopNav.tsx (3)

6-6: Import cleanup aligns with TopNav removal

Dropping SidebarTrigger from this file and only using SidebarInset/SidebarProvider is consistent with the new sidebar UX.


32-32: Padding change is sensible after removing TopNav

Adding pt-9 on SidebarInset provides breathing room where TopNav used to be.


21-25: No update needed for setup route

The SideNavWithTopNav wrapper 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]/onboarding should hide the nav, so the existing conditional is correct.

apps/web/components/SideNav.tsx (3)

44-47: New imports are appropriate and used

SidebarTrigger, 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 placed

Conditionally 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 sidebar

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

Comment on lines 208 to +218
<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>
)}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

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
Copy link

claude bot commented Aug 18, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/web/components/SideNav.tsx (1)

193-203: Fix nested interactive elements and account-scope the setup link

SidebarTrigger 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 theme

Using 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 safety

For 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.email

NextAuth 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-scoped

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

📥 Commits

Reviewing files that changed from the base of the PR and between 99c998b and 0f3e93b.

📒 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.tsx
  • apps/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
Use result?.serverError with toastError and toastSuccess
Use LoadingContent component to handle loading and error states consistently
Pass loading, error, and children props to LoadingContent

Files:

  • apps/web/components/NavUser.tsx
  • apps/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 LoadingContent component 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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/web/components/SideNav.tsx
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/logging.mdc)

**/*.{ts,tsx}: Use createScopedLogger for logging in backend TypeScript files
Typically add the logger initialization at the top of the file when using createScopedLogger
Only use .with() on a logger instance within a specific function, not for a global logger

Import 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.tsx
  • apps/web/components/SideNav.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use elements 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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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 solid

Good use of DropdownMenu primitives, account-scoped links via prefixPath, and provider-gated items.

apps/web/components/SideNav.tsx (2)

207-209: SetupProgressCard placement LGTM

Conditionally 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 LGTM

NavUser in the footer is a good fit and consolidates user controls in the sidebar per the new IA.

@claude
Copy link

claude bot commented Aug 18, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

@claude
Copy link

claude bot commented Aug 18, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

@elie222 elie222 merged commit 57be2e8 into main Aug 18, 2025
11 of 13 checks passed
@elie222 elie222 deleted the feat/setup-card branch December 18, 2025 23:04
@coderabbitai coderabbitai bot mentioned this pull request Dec 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments