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 that can be reviewed per hour. Please wait 19 minutes and 59 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)
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds a three-step Meeting Briefs onboarding flow (calendar connect, send test brief, readiness/checkout), pages/routes, pricing toggle and discount badge, UTM tracking consolidation via registerUtmTracking, optional priceId support in checkout action, Stripe price IDs for “Brief My Meeting”, and small navigation metadata updates. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ServerPage as Onboarding Page (server)
participant Browser as Client/Router
participant Step1 as StepConnectCalendar (client)
participant Calendars as Calendars Hook/API
participant Step2 as StepSendTestBrief (client)
participant Events as Events Hook/API
participant Step3 as StepReady (client)
participant CheckoutAction as generateCheckoutSessionAction
User->>ServerPage: GET /{emailAccountId}/onboarding-brief?step=1
ServerPage-->>Browser: render MeetingBriefsOnboardingContent (step=1)
Browser->>Step1: mount -> useCalendars()
Step1->>Calendars: fetch connections
alt calendar connected
Calendars-->>Step1: connected
Step1->>Browser: router.push(step=2)
else not connected
Step1-->>User: show ConnectCalendar
User->>Step1: connect -> onNext -> Browser navigates step=2
end
Browser->>Step2: mount -> useCalendarUpcomingEvents()
Step2->>Events: fetch events
Events-->>Step2: events list
User->>Step2: select event & Send Test Brief
Step2->>Step2: invoke sendBriefAction -> success
Step2-->>Browser: after success router.push(step=3)
Browser->>Step3: mount (pricing)
User->>Step3: Start Free Trial (choose frequency)
Step3->>CheckoutAction: request checkout (priceId or tier)
CheckoutAction-->>Step3: returns checkout URL
Step3->>Browser: redirect to Stripe checkout
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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. Comment |
Add a 3-step meeting briefs onboarding flow and set a 180s
|
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx
Show resolved
Hide resolved
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on January 28
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
apps/web/components/SideNavWithTopNav.tsx (1)
60-64: Logic correctly extends onboarding path handling.The addition of "onboarding-brief" to the early-return condition is functionally correct and aligns with the new onboarding flow. The logic safely checks for two-segment paths and renders children directly for both onboarding variants.
Optional: Extract onboarding paths to a constant
While you've noted this is temporary code (line 57), consider extracting the path segments to a constant for easier maintenance:
+ const ONBOARDING_PATHS = ["onboarding", "onboarding-brief"]; + // Ugly code. May change the onboarding path later so we don't need to do this. // Only return children for the main onboarding page: /[emailAccountId]/onboarding const segments = pathname.split("/").filter(Boolean); if ( segments.length === 2 && - (segments[1] === "onboarding" || segments[1] === "onboarding-brief") + ONBOARDING_PATHS.includes(segments[1]) ) return children;This makes it easier to add or modify onboarding paths in the future.
apps/web/app/(landing)/onboarding-brief/page.tsx (1)
1-5: LGTM! Clean redirect implementation.The redirect logic is correct and appropriately delegates to the
redirectToEmailAccountPathutility. The implementation follows Next.js App Router patterns and maintains good separation of concerns.
Optional enhancement: Consider adding metadata for SEO, though it's not critical for a redirect-only page:
Optional metadata export
import { redirectToEmailAccountPath } from "@/utils/account"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Meeting Briefs Onboarding", +}; export default async function OnboardingBriefPage() { await redirectToEmailAccountPath("/onboarding-brief"); }apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx (1)
26-33: Unnecessaryasynckeyword.The
onNextcallback doesn't useawait, so theasynckeyword is redundant and can be removed for clarity.🔎 Suggested fix
- const onNext = useCallback(async () => { + const onNext = useCallback(() => { if (clampedStep < TOTAL_STEPS) { const nextStep = clampedStep + 1; router.push( prefixPath(emailAccountId, `/onboarding-brief?step=${nextStep}`), ); } }, [router, emailAccountId, clampedStep]);apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (1)
69-79: Hardcoded pricing values may become stale.The prices ($7.50, $9, $90/year) are hardcoded rather than derived from a configuration. If these are intentionally separate from the main pricing tiers, consider extracting them to a config constant for easier maintenance.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(app)/premium/Pricing.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/components/SideNav.tsxapps/web/components/SideNavWithTopNav.tsx
💤 Files with no reviewable changes (1)
- apps/web/components/SideNav.tsx
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor error handling in async operations
**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
**/*.{ts,tsx}: For early access feature flags, create hooks using the naming conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g.,inbox-cleaner,pricing-options-2)
Always define types for A/B test variant flags (e.g.,type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
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 TypeScript namespaces
Don't use non-null assertions with the!postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
apps/web/app/(app)/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g.,
import groupBy from 'lodash/groupBy')
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
**/*.{tsx,ts,css}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
Implement responsive design with Tailwind CSS using a mobile-first approach
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-hidden="true"on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like<marquee>or<blink>
Only use thescopeprop on<th>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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
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 AR...
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
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 forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use bothchildrenanddangerouslySetInnerHTMLprops on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use<>...</>instead of<Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't usetarget="_blank"withoutrel="noopener"
Don't use<img>elements in Next.js projects
Don't use<head>elements in Next.js projects
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
!(pages/_document).{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't use the next/head module in pages/_document.js on Next.js projects
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g.,import groupBy from 'lodash/groupBy')
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
apps/web/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor error handling in forms
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/components/SideNavWithTopNav.tsxapps/web/app/(app)/premium/config.tsapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/premium/PricingFrequencyToggle.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
apps/web/components/**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)
Use
LoadingContentcomponent to consistently handle loading and error states, passingloading,error, andchildrenpropsUse PascalCase for component file names (e.g.,
components/Button.tsx)
Files:
apps/web/components/SideNavWithTopNav.tsx
**/{pages,routes,components}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/gmail-api.mdc)
Never call Gmail API directly from routes or components - always use wrapper functions from the utils folder
Files:
apps/web/components/SideNavWithTopNav.tsx
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma'sselectoption. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. AllfindUnique/findFirstcalls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
AllfindManyqueries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g.,emailAccount: { id: emailAccountId }) to validate ownership
Files:
apps/web/app/(app)/premium/config.ts
apps/web/**/*.{example,ts,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Add environment variables to
.env.example,env.ts, andturbo.json
Files:
apps/web/app/(app)/premium/config.ts
🧠 Learnings (38)
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 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]/onboarding-brief/StepConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(landing)/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Make sure all anchors are valid and navigable
Applied to files:
apps/web/components/SideNavWithTopNav.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{jsx,tsx} : Don't use unnecessary fragments
Applied to files:
apps/web/components/SideNavWithTopNav.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : Components for the page are either put in `page.tsx`, or in the `apps/web/app/(app)/PAGE_NAME` folder
Applied to files:
apps/web/components/SideNavWithTopNav.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/components/ui/**/*.tsx : Shadcn UI components are located in `components/ui` directory
Applied to files:
apps/web/components/SideNavWithTopNav.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/app/**/*.{ts,tsx} : Follow NextJS app router structure with (app) directory
Applied to files:
apps/web/components/SideNavWithTopNav.tsxapps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/app/**/[!.]*/route.{ts,tsx} : Use kebab-case for route directories in Next.js App Router (e.g., `api/hello-world/route`)
Applied to files:
apps/web/components/SideNavWithTopNav.tsxapps/web/app/(landing)/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*.tsx : Use `LoadingContent` component to consistently handle loading and error states, passing `loading`, `error`, and `children` props
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Use the `LoadingContent` component to handle loading states
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withAuth` middleware for user-level operations (user settings, API keys, referrals) - provides only `userId` in `request.auth`
Applied to files:
apps/web/app/(landing)/welcome/utms.tsx
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{app,pages}/**/{route,+page}.{ts,tsx} : Use middleware wrappers (withError, withAuth, withEmailAccount, withEmailProvider) that automatically create loggers with request context in API routes
Applied to files:
apps/web/app/(landing)/welcome/utms.tsx
📚 Learning: 2025-11-25T14:42:16.602Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:16.602Z
Learning: The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests
Applied to files:
apps/web/app/(landing)/welcome/utms.tsx
📚 Learning: 2025-11-25T14:42:11.919Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:11.919Z
Learning: Applies to utils/**/*.{js,ts,jsx,tsx} : The `utils` folder contains core app logic such as Next.js Server Actions and Gmail API requests
Applied to files:
apps/web/app/(landing)/welcome/utms.tsxapps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withAuth` middleware for user-level operations such as user settings, API keys, and referrals that use only `userId`
Applied to files:
apps/web/app/(landing)/welcome/utms.tsx
📚 Learning: 2025-11-25T14:37:11.434Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/get-api-route.mdc:0-0
Timestamp: 2025-11-25T14:37:11.434Z
Learning: Applies to **/app/**/route.ts : Always wrap GET API route handlers with `withAuth` or `withEmailAccount` middleware for consistent error handling and authentication in Next.js App Router
Applied to files:
apps/web/app/(landing)/welcome/utms.tsxapps/web/app/(landing)/onboarding-brief/page.tsx
📚 Learning: 2025-06-05T09:49:12.168Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 485
File: apps/web/app/(landing)/login/page.tsx:41-43
Timestamp: 2025-06-05T09:49:12.168Z
Learning: In Next.js App Router, components that use the `useSearchParams` hook require a Suspense boundary to handle the asynchronous nature of search parameter access. The Suspense wrapper is necessary and should not be removed when a component uses useSearchParams.
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsxapps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-08-10T22:03:30.507Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 667
File: apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx:18-25
Timestamp: 2025-08-10T22:03:30.507Z
Learning: In Next.js 15, both `params` and `searchParams` passed to page components in the App Router are Promises that need to be awaited. They should be typed as `Promise<{...}>` and accessed using `await` in server components or React's `use()` hook in client components. This is different from Next.js 14 where they were plain objects.
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : For API get requests to server, use the `swr` package with `useSWR` hook
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsxapps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:36:40.146Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:40.146Z
Learning: Applies to **/*{.action,.server}.{ts,tsx} : For mutating data, use Next.js server actions
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.{tsx,ts} : For API GET requests to server, use the `swr` package with hooks like `useSWR` to fetch data
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:36:36.276Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-11-25T14:36:36.276Z
Learning: For mutating data, use Next.js server actions instead of SWR
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to !(pages/_document).{jsx,tsx} : Don't use the next/head module in pages/_document.js on Next.js projects
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx`
Applied to files:
apps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx`
Applied to files:
apps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx` with components either colocated in the same folder or in `page.tsx`
Applied to files:
apps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : Components for pages are either put in `page.tsx`, or in the `apps/web/app/(app)/PAGE_NAME` folder
Applied to files:
apps/web/app/(landing)/onboarding-brief/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Pages are Server components so you can load data into them directly
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/app/*/page.tsx : Pages must be Server components that load data directly
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx
📚 Learning: 2025-11-25T14:38:32.328Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/posthog-feature-flags.mdc:0-0
Timestamp: 2025-11-25T14:38:32.328Z
Learning: Applies to **/*.{ts,tsx} : Always define types for A/B test variant flags (e.g., `type PricingVariant = "control" | "variant-a" | "variant-b"`) and provide type safety through type casting
Applied to files:
apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive
Applied to files:
apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Prefer functional components with hooks in React
Applied to files:
apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : If you need to use `onClick` in a component, that component is a client component and file must start with `use client`
Applied to files:
apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2024-08-23T11:37:26.779Z
Learnt from: aryanprince
Repo: elie222/inbox-zero PR: 210
File: apps/web/app/(app)/stats/NewsletterModal.tsx:2-4
Timestamp: 2024-08-23T11:37:26.779Z
Learning: `MoreDropdown` is a React component and `useUnsubscribeButton` is a custom React hook, and they should not be imported using `import type`.
Applied to files:
apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/hooks/use*.ts : Use SWR hooks for client-side data fetching, with hooks stored in `apps/web/hooks/use*.ts` that return typed responses from GET API routes
Applied to files:
apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use React Hook Form with Zod validation for form handling
Applied to files:
apps/web/app/(app)/premium/Pricing.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/hooks/**/*.{ts,tsx} : Use SWR for client-side data fetching with type-safe response types from GET API routes
Applied to files:
apps/web/app/(app)/premium/Pricing.tsx
🧬 Code graph analysis (8)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx (2)
apps/web/hooks/useCalendars.ts (1)
useCalendars(4-6)apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx (1)
ConnectCalendar(12-111)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx (5)
apps/web/providers/EmailAccountProvider.tsx (1)
useAccount(79-89)apps/web/app/(app)/[emailAccountId]/onboarding/OnboardingWrapper.tsx (1)
OnboardingWrapper(3-22)apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx (1)
StepConnectCalendar(11-61)apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (1)
StepSendTestBrief(18-187)apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (1)
StepReady(31-124)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (6)
apps/web/providers/EmailAccountProvider.tsx (1)
useAccount(79-89)apps/web/hooks/useCalendarUpcomingEvents.tsx (1)
useCalendarUpcomingEvents(4-8)apps/web/utils/actions/meeting-briefs.ts (1)
sendBriefAction(40-94)apps/web/components/Typography.tsx (1)
TypographyP(129-129)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-31)apps/web/utils/email.ts (1)
extractDomainFromEmail(73-91)
apps/web/app/(landing)/welcome/utms.tsx (1)
apps/web/utils/auth.ts (1)
auth(516-517)
apps/web/app/(app)/premium/PricingFrequencyToggle.tsx (1)
apps/web/components/Input.tsx (1)
Label(116-132)
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx (2)
apps/web/app/(landing)/welcome/utms.tsx (1)
registerUtmTracking(18-34)apps/web/utils/auth.ts (1)
auth(516-517)
apps/web/app/(landing)/onboarding-brief/page.tsx (1)
apps/web/utils/account.ts (1)
redirectToEmailAccountPath(136-160)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx (4)
apps/web/app/(app)/[emailAccountId]/onboarding/page.tsx (1)
metadata(11-15)apps/web/app/(landing)/welcome/utms.tsx (1)
registerUtmTracking(18-34)apps/web/utils/auth.ts (1)
auth(516-517)apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx (1)
MeetingBriefsOnboardingContent(18-42)
⏰ 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). (5)
- GitHub Check: Baz Reviewer
- GitHub Check: cubic · AI code reviewer
- GitHub Check: Cursor Bugbot
- GitHub Check: Macroscope - Correctness Check
- GitHub Check: test
🔇 Additional comments (22)
apps/web/app/(landing)/welcome/utms.tsx (3)
1-16: LGTM: Clean imports and type definitions.The imports are properly organized, using type-only imports where appropriate. The scoped logger at the file level correctly avoids using
.with(), and theUtmValuestype definition is clear and appropriate.
18-34: LGTM: Well-designed UTM tracking orchestration.The
registerUtmTrackingfunction correctly separates synchronous cookie extraction from deferred persistence usingafter(). The pattern of passingauthPromiseand resolving it inside theafter()callback is safe becauseauth()invokesheaders()immediately when called (before the promise is returned), ensuring request APIs are accessed before the response is sent.
40-92: LGTM: Robust helper functions with proper error handling.The helper functions are well-structured:
extractUtmValuessafely reads cookies with optional chainingfetchUserAndStoreUtmsincludes proper error handling and guards against duplicate storagestoreUtmsis appropriately scoped as internal with comprehensive loggingapps/web/app/(app)/[emailAccountId]/onboarding/page.tsx (3)
1-15: LGTM: Correct imports and metadata.The import changes correctly reflect the refactoring, replacing inline UTM logic with the centralized
registerUtmTrackingutility. The metadata export is properly structured with title, description, and canonical URL.
21-32: LGTM: Efficient async handling and correct UTM tracking integration.The
Promise.allpattern efficiently resolves multiple async operations concurrently, correctly treatingparamsandsearchParamsas Promises per Next.js 15 requirements. TheregisterUtmTrackingcall properly passes the auth promise and awaited cookie store, aligning with the function's design to defer UTM persistence while returning values immediately.
34-36: LGTM: Clean conditional routing logic.The conditional redirect correctly routes "briefmymeeting" UTM sources to the specialized onboarding flow while providing a
forceparameter escape hatch. The redirect usesnext/navigation'sredirect()function appropriately for the App Router, and the deferred UTM persistence inregisterUtmTrackingwill complete even after the redirect occurs (per Next.jsafter()behavior).apps/web/app/(app)/premium/config.ts (1)
66-68: LGTM!The new price IDs for the "brief my meeting" feature are correctly added to the
oldPriceIdsarrays, following the existing pattern. This ensures proper handling of subscriptions created with these price IDs.Also applies to: 77-79
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx (2)
18-26: LGTM!The auto-advancement logic is well-implemented with proper cleanup. The
hasAdvancedflag correctly prevents duplicate navigation, and the timer is properly cleared on unmount. The parent component memoizesonNextwithuseCallback, ensuring stable reference.
44-58: Clean conditional rendering with good UX feedback.The connected state provides clear visual feedback with the checkmark and animation. The "Continue" button allows manual progression if the user doesn't want to wait for auto-advancement.
apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx (2)
15-23: Well-structured server component following Next.js 15 patterns.The async
paramsandsearchParamsare correctly typed as Promises. Note thatparamsis defined but not awaited or used in this component - theemailAccountIdis accessed by child components via theuseAccounthook instead. This is fine but could be simplified by removing the unusedparamstype if truly not needed.
25-28: LGTM!UTM tracking is correctly registered. The
registerUtmTrackingfunction uses Next.jsafter()internally to defer the tracking work, so it won't block rendering.apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx (1)
35-41: LGTM!The step-based rendering is clean and follows a forward-only flow pattern. The
OnboardingWrapperprovides consistent styling across all steps.apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (3)
24-39: Good error handling following project conventions.The
useActionhook is properly configured withtoastSuccessandtoastErrorhandlers. The error handling correctly accesseserr.serverErrorwith a fallback message, as per coding guidelines.
100-157: Well-implemented selectable event list with good defensive coding.The event list handles edge cases properly -
extractDomainFromEmailsafely handles empty attendees arrays via the|| ""fallback. The button elements correctly specifytype="button"as required by coding guidelines.
162-184: LGTM!The send button has comprehensive state management - disabled when no event is selected, during execution, or after successful send. The visual feedback (loading spinner, green variant on success) provides clear UX.
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (1)
105-120: LGTM!The Gmail-specific link is correctly guarded by
isGoogleProvidercheck and includes propertarget="_blank"withrel="noopener noreferrer"for security.apps/web/app/(app)/premium/PricingFrequencyToggle.tsx (3)
6-19: Well-designed type-safe frequency configuration.The
as constassertions enable proper type inference, and theFrequencytype is correctly derived from the array. This pattern provides type safety while keeping the data as the single source of truth.
34-54: LGTM!The RadioGroup implementation provides good accessibility with the
sr-onlylabel for screen readers. The Headless UI components handle keyboard navigation automatically.
60-65: Clean reusable badge component.
DiscountBadgeis appropriately extracted as a simple, reusable styled wrapper.apps/web/app/(app)/premium/Pricing.tsx (3)
127-134: Clean integration of the reusable frequency toggle.The
PricingFrequencyToggleis well-integrated using the children slot pattern for the discount badge, maintaining the existing layout.
203-203: Good DRY improvement.Using
DiscountBadgeconsistently for both "Popular" and "SAVE X%" badges eliminates duplicate styling code.Also applies to: 225-229
41-56: No action needed. The Pricing component is already properly wrapped in a Suspense boundary through AppPricingLazy.tsx, which usesdynamic()from next/dynamic and a Suspense wrapper with a Loading fallback. The useSearchParams hook has the required Suspense boundary and will not cause hydration issues.Likely an incorrect or invalid review comment.
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
4 issues found across 13 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/components/SideNavWithTopNav.tsx">
<violation number="1" location="apps/web/components/SideNavWithTopNav.tsx:62">
P3: The comment above this condition is now outdated. It states the code only handles `/[emailAccountId]/onboarding` but it now also handles `onboarding-brief`. Consider updating the comment to reflect both paths.</violation>
</file>
<file name="apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx:24">
P2: When an invalid step parameter is provided (e.g., `?step=abc`), `Number.parseInt` returns `NaN`, and `Math.max(NaN, 1)` also returns `NaN`. Since `NaN` doesn't match any step comparison, no component renders, leaving users with a blank page. Add a fallback to default to step 1 when the value is NaN.</violation>
</file>
<file name="apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx:100">
P1: The `onNext` prop is received but never used. The "Start Free Trial" button has no `onClick` handler, which will leave users stuck on this screen with no way to proceed through the onboarding flow. Based on other Step components (e.g., `StepDigest.tsx`), the button should call `onNext` when clicked.</violation>
</file>
<file name="apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/onboarding-brief/page.tsx:23">
P2: `Number.parseInt` with an invalid string returns `NaN`, which won't fall back to `1`. This could cause no step content to render. Consider using `|| 1` to handle `NaN` cases.</violation>
</file>
Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
Show resolved
Hide resolved
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
Outdated
Show resolved
Hide resolved
| value={frequency} | ||
| onChange={setFrequency} | ||
| className="grid grid-cols-2 gap-x-1 rounded-full p-1 text-center text-xs font-semibold leading-5 ring-1 ring-inset ring-gray-200" | ||
| > | ||
| <Label className="sr-only">Payment frequency</Label> | ||
| {frequencies.map((option) => ( | ||
| <Radio | ||
| key={option.value} | ||
| value={option} | ||
| className={({ checked }) => |
There was a problem hiding this comment.
RadioGroup compares by reference, so using the full object for value prevents the checked state when a different instance is passed. Consider using the primitive option.value and frequency.value, mapping onChange back to a Frequency.
| value={frequency} | |
| onChange={setFrequency} | |
| className="grid grid-cols-2 gap-x-1 rounded-full p-1 text-center text-xs font-semibold leading-5 ring-1 ring-inset ring-gray-200" | |
| > | |
| <Label className="sr-only">Payment frequency</Label> | |
| {frequencies.map((option) => ( | |
| <Radio | |
| key={option.value} | |
| value={option} | |
| className={({ checked }) => | |
| value={frequency.value} | |
| onChange={(v) => setFrequency(frequencies.find((f) => f.value === v)!)} | |
| className="grid grid-cols-2 gap-x-1 rounded-full p-1 text-center text-xs font-semibold leading-5 ring-1 ring-inset ring-gray-200" | |
| > | |
| <Label className="sr-only">Payment frequency</Label> | |
| {frequencies.map((option) => ( | |
| <Radio | |
| key={option.value} | |
| value={option.value} | |
| className={({ checked }) => |
🚀 Want me to fix this? Reply ex: "fix it for me".
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (1)
134-142: LGTM! Checkout flow properly implemented.The "Start Free Trial" button correctly handles the checkout flow with
onClick={handleCheckout}and manages loading state. This resolves the issues flagged in previous reviews about the missing click handler.
🧹 Nitpick comments (3)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx (3)
39-39: Consider using a named default instead of array index.Using
frequencies[1]is fragile—if thefrequenciesarray order changes, the default will shift unexpectedly. Consider using a named constant or finding by value (e.g.,frequencies.find(f => f.value === "annually")) for clarity and robustness.🔎 Suggested refactor
- const [frequency, setFrequency] = useState(frequencies[1]); + const [frequency, setFrequency] = useState( + frequencies.find(f => f.value === "annually") ?? frequencies[0] + );
62-63: Log the caught error for debugging.The catch block shows a generic error message but doesn't log or pass the actual error. This makes debugging checkout failures difficult in production.
🔎 Suggested fix
- } catch { + } catch (error) { + console.error("Checkout error:", error); toastError({ description: "Error creating checkout session" }); } finally {
104-112: Consider extracting hardcoded prices to constants.The monthly ($9) and annual ($7.50/$90) prices are hardcoded strings. If these prices need to change, you'll have to update multiple locations. Consider extracting them to named constants at the top of the file.
🔎 Example refactor
+const MEETING_BRIEFS_PRICING = { + monthly: { amount: 9, display: "$9" }, + annually: { amount: 7.5, display: "$7.50", yearly: "$90" } +} as const; + export function StepReady() { // ... <p className="text-3xl font-bold text-foreground mt-1"> - ${frequency.value === "annually" ? "7.50" : "9"} + {frequency.value === "annually" + ? MEETING_BRIEFS_PRICING.annually.display + : MEETING_BRIEFS_PRICING.monthly.display}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/app/(app)/[emailAccountId]/onboarding-brief/MeetingBriefsOnboardingContent.tsx
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor error handling in async operations
**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
**/*.{ts,tsx}: For early access feature flags, create hooks using the naming conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g.,inbox-cleaner,pricing-options-2)
Always define types for A/B test variant flags (e.g.,type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
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 TypeScript namespaces
Don't use non-null assertions with the!postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
apps/web/app/(app)/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g.,
import groupBy from 'lodash/groupBy')
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
**/*.{tsx,ts,css}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
Implement responsive design with Tailwind CSS using a mobile-first approach
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-hidden="true"on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like<marquee>or<blink>
Only use thescopeprop on<th>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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
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 AR...
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
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 forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use bothchildrenanddangerouslySetInnerHTMLprops on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use<>...</>instead of<Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't usetarget="_blank"withoutrel="noopener"
Don't use<img>elements in Next.js projects
Don't use<head>elements in Next.js projects
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
!(pages/_document).{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't use the next/head module in pages/_document.js on Next.js projects
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g.,import groupBy from 'lodash/groupBy')
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
apps/web/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.ts
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor error handling in forms
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsxapps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma'sselectoption. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. AllfindUnique/findFirstcalls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
AllfindManyqueries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g.,emailAccount: { id: emailAccountId }) to validate ownership
Files:
apps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
apps/web/**/*.{example,ts,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Add environment variables to
.env.example,env.ts, andturbo.json
Files:
apps/web/app/(app)/premium/config.tsapps/web/utils/actions/premium.ts
apps/web/utils/actions/*.ts
📄 CodeRabbit inference engine (.cursor/rules/fullstack-workflow.mdc)
apps/web/utils/actions/*.ts: Usenext-safe-actionwith Zod schemas for all server actions (create/update/delete mutations), storing validation schemas inapps/web/utils/actions/*.validation.ts
Server actions should use 'use server' directive and automatically receive authentication context (emailAccountId) from theactionClient
apps/web/utils/actions/*.ts: Create corresponding server action implementation files using the naming conventionapps/web/utils/actions/NAME.tswith 'use server' directive
Use 'use server' directive at the top of server action implementation files
Implement all server actions using thenext-safe-actionlibrary with actionClient, actionClientUser, or adminActionClient for type safety and validation
UseactionClientUserwhen only authenticated user context (userId) is needed
UseactionClientwhen both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client
UseadminActionClientfor actions restricted to admin users
Add metadata with a meaningful action name using.metadata({ name: "actionName" })for Sentry instrumentation and monitoring
Use.schema()method with Zod validation schemas from corresponding.validation.tsfiles in next-safe-action configuration
Access context (userId, emailAccountId, etc.) via thectxobject parameter in the.action()handler
UserevalidatePathorrevalidateTagfrom 'next/cache' within server action handlers when mutations modify data displayed elsewhere
Files:
apps/web/utils/actions/premium.ts
apps/web/utils/actions/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
apps/web/utils/actions/**/*.ts: Server actions must be located inapps/web/utils/actionsfolder
Server action files must start withuse serverdirective
apps/web/utils/actions/**/*.ts: Use proper error handling with try/catch blocks
Usenext-safe-actionwith Zod schemas for server actions to handle mutations
UserevalidatePathin server actions for cache invalidation after mutations
Files:
apps/web/utils/actions/premium.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
Logger should be passed as a parameter to helper functions instead of creating their own logger instances
Files:
apps/web/utils/actions/premium.ts
apps/web/utils/actions/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Infer types from Zod schemas using
z.infer<typeof schema>instead of duplicating as separate interfaces
Files:
apps/web/utils/actions/premium.ts
🧠 Learnings (5)
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 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]/onboarding-brief/StepReady.tsx
📚 Learning: 2025-11-25T14:42:08.869Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-11-25T14:42:08.869Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Accompany `onClick` with at least one of: `onKeyUp`, `onKeyDown`, or `onKeyPress`
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If you need to use `onClick` in a component, that component must be a client component and file must start with `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Components with `onClick` handlers must be client components marked with the `use client` directive
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepReady.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `next-safe-action` with Zod schemas for all server actions (create/update/delete mutations), storing validation schemas in `apps/web/utils/actions/*.validation.ts`
Applied to files:
apps/web/utils/actions/premium.ts
🧬 Code graph analysis (1)
apps/web/utils/actions/premium.ts (5)
apps/web/app/(app)/premium/config.ts (1)
getStripePriceId(119-125)apps/web/utils/error.ts (1)
SafeError(87-97)apps/web/ee/billing/stripe/index.ts (1)
getStripe(7-20)apps/web/utils/posthog.ts (2)
trackStripeCustomerCreated(137-149)trackStripeCheckoutCreated(151-153)apps/web/env.ts (1)
env(17-258)
⏰ 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). (5)
- GitHub Check: cubic · AI code reviewer
- GitHub Check: Baz Reviewer
- GitHub Check: test
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Macroscope - Correctness Check
🔇 Additional comments (3)
apps/web/app/(app)/premium/config.ts (1)
42-45: Verify these Stripe price IDs exist in your Stripe account.The constants
BRIEF_MY_MEETING_PRICE_ID_MONTHLYandBRIEF_MY_MEETING_PRICE_ID_ANNUALLYare used as legacy/old price IDs in theBUSINESS_MONTHLYandBUSINESS_ANNUALLYtier configurations and in the checkout flow. Confirm these IDs are active in Stripe and correctly handle existing subscriptions migrating from the "Brief My Meeting" product.apps/web/utils/actions/premium.ts (2)
502-525: LGTM! Good use of idempotency key for Stripe customer creation.The idempotency key pattern on Line 510 correctly prevents race conditions when creating Stripe customers. The flow properly handles both existing and new premium records.
527-548: LGTM! Checkout session creation follows standard patterns.The quantity calculation on Line 528 correctly handles edge cases with proper fallback to 1. The checkout session configuration is standard and includes appropriate metadata for tracking.
Minor note: The 7-day trial period (Line 536) is hardcoded. Consider extracting to a config constant if this may vary by tier or campaign in the future.
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/app/(app)/[emailAccountId]/calendars/page.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/calendars/page.tsx:18">
P2: Potential open redirect vulnerability. The `returnPath` from the cookie is used directly in `redirect()` without validating it's an internal path. Consider validating that the path starts with `/` and doesn't start with `//` to prevent redirects to external sites.</violation>
</file>
Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/app/(app)/[emailAccountId]/calendars/page.tsx">
<violation number="1" location="apps/web/app/(app)/[emailAccountId]/calendars/page.tsx:19">
P1: The cookie deletion was removed, which can cause redirect loops for valid paths and leaves stale/malicious cookies for invalid paths. The cookie should be deleted regardless of whether the path is internal or not.</violation>
</file>
Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (1)
28-31: Use optional chaining to safely access result.The
onSuccesscallback readsresult.messagewithout verifyingresultexists, which could cause a runtime error if the action response is undefined.🔎 Proposed fix
- description: result.message || "Test brief sent! Check your inbox.", + description: result?.message ?? "Test brief sent! Check your inbox.",apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx (1)
12-56: Wrap async data in LoadingContent component.The component uses
useCalendars(SWR) but doesn't handle loading or error states. This causes the "Connect Calendar" UI to flash even when a calendar is already connected, and silently ignores fetch errors.As per coding guidelines and the past review comment, wrap the content in
LoadingContentto properly handle these states.Based on coding guidelines: "Use LoadingContent component for async data with loading and error states"
🔎 Proposed fix
export function StepConnectCalendar({ onNext }: { onNext: () => void }) { const { emailAccountId } = useAccount(); - const { data: calendarsData } = useCalendars(); + const { data: calendarsData, isLoading, error } = useCalendars(); const hasCalendarConnected = calendarsData?.connections && calendarsData.connections.length > 0; return ( - <> + <LoadingContent loading={isLoading} error={error}> <div className="flex justify-center"> <IconCircle size="lg"> <Calendar className="size-6" /> </IconCircle> </div> <div className="text-center"> <PageHeading className="mt-4">Connect Your Calendar</PageHeading> <TypographyP className="mt-2 max-w-lg mx-auto"> We'll automatically detect your upcoming meetings with external guests and prepare personalized briefings. </TypographyP> </div> <div className="flex flex-col items-center justify-center mt-8 gap-4"> {hasCalendarConnected ? ( <> <div className="flex items-center gap-2 text-green-600 font-medium animate-in fade-in zoom-in duration-300"> <CheckIcon className="h-5 w-5" /> Calendar Connected! </div> <Button onClick={onNext} className="mt-2"> Continue </Button> </> ) : ( <ConnectCalendar onboardingReturnPath={prefixPath( emailAccountId, "/onboarding-brief?step=2", )} /> )} </div> - </> + </LoadingContent> ); }Don't forget to add the import:
+"use client"; + +import { Calendar, CheckIcon } from "lucide-react"; +import { PageHeading, TypographyP } from "@/components/Typography"; +import { useCalendars } from "@/hooks/useCalendars"; +import { IconCircle } from "@/app/(app)/[emailAccountId]/onboarding/IconCircle"; +import { ConnectCalendar } from "@/app/(app)/[emailAccountId]/calendars/ConnectCalendar"; +import { Button } from "@/components/ui/button"; +import { useAccount } from "@/providers/EmailAccountProvider"; +import { prefixPath } from "@/utils/path"; ++import { LoadingContent } from "@/components/LoadingContent";
🧹 Nitpick comments (1)
apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsx (1)
23-27: Consider adding SameSite attribute to the cookie.The cookie implementation is functional and secure. For additional CSRF protection, consider adding
SameSite=Laxto the cookie attributes.🔎 Proposed enhancement
const setOnboardingReturnCookie = () => { if (onboardingReturnPath) { - document.cookie = `${CALENDAR_ONBOARDING_RETURN_COOKIE}=${encodeURIComponent(onboardingReturnPath)}; path=/; max-age=180`; + document.cookie = `${CALENDAR_ONBOARDING_RETURN_COOKIE}=${encodeURIComponent(onboardingReturnPath)}; path=/; max-age=180; SameSite=Lax`; } };
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/accounts/page.tsxapps/web/utils/calendar/constants.ts
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)
**/*.{ts,tsx}: For API GET requests to server, use theswrpackage
Useresult?.serverErrorwithtoastErrorfrom@/components/Toastfor error handling in async operations
**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls
**/*.{ts,tsx}: For early access feature flags, create hooks using the naming conventionuse[FeatureName]Enabledthat return a boolean fromuseFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming conventionuse[FeatureName]Variantthat define variant types, useuseFeatureFlagVariantKey()with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g.,inbox-cleaner,pricing-options-2)
Always define types for A/B test variant flags (e.g.,type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
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 TypeScript namespaces
Don't use non-null assertions with the!postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Useas constinstead of literal types and type annotations
Use eitherT[]orArray<T>consistently
Initialize each enum member value explicitly
Useexport typefor types
Use `impo...
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)
Always import Prisma enums from
@/generated/prisma/enumsinstead of@/generated/prisma/clientto avoid Next.js bundling errors in client componentsImport Prisma using the project's centralized utility:
import prisma from '@/utils/prisma'
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g.,
import groupBy from 'lodash/groupBy')
apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/security.mdc)
**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma'sselectoption. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. AllfindUnique/findFirstcalls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
AllfindManyqueries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g.,emailAccount: { id: emailAccountId }) to validate ownership
Files:
apps/web/utils/calendar/constants.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Usenext/imagepackage for images
For API GET requests to server, use theswrpackage with hooks likeuseSWRto fetch data
For text inputs, use theInputcomponent withregisterPropsfor form integration and error handling
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{tsx,ts,css}
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
Implement responsive design with Tailwind CSS using a mobile-first approach
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{js,jsx,ts,tsx}: Don't useaccessKeyattribute on any HTML element
Don't setaria-hidden="true"on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like<marquee>or<blink>
Only use thescopeprop on<th>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 assigntabIndexto non-interactive HTML elements
Don't use positive integers fortabIndexproperty
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 atitleelement 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
AssigntabIndexto non-interactive HTML elements witharia-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 atypeattribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden)
Always include alangattribute on the html element
Always include atitleattribute for iframe elements
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
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 AR...
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
!(pages/_document).{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't use the next/head module in pages/_document.js on Next.js projects
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g.,import groupBy from 'lodash/groupBy')
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/{utils,helpers,lib}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)
Logger should be passed as a parameter to helper functions instead of creating their own logger instances
Files:
apps/web/utils/calendar/constants.ts
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{ts,tsx,js,jsx}: Use@/path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/**/*.{ts,tsx,js,jsx,json,css}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Format code with Prettier
Files:
apps/web/utils/calendar/constants.tsapps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/**/*.{example,ts,json}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Add environment variables to
.env.example,env.ts, andturbo.json
Files:
apps/web/utils/calendar/constants.ts
apps/web/app/(app)/*/page.tsx
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
apps/web/app/(app)/*/page.tsx: Create new pages atapps/web/app/(app)/PAGE_NAME/page.tsx
Pages are Server components so you can load data into them directlyCreate new pages at
apps/web/app/(app)/PAGE_NAME/page.tsxwith components either colocated in the same folder or inpage.tsx
Files:
apps/web/app/(app)/accounts/page.tsx
apps/web/app/(app)/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/page-structure.mdc)
apps/web/app/(app)/**/*.{ts,tsx}: Components for the page are either put inpage.tsx, or in theapps/web/app/(app)/PAGE_NAMEfolder
If we're in a deeply nested component we will useswrto fetch via API
If you need to useonClickin a component, that component is a client component and file must start withuse client
Files:
apps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)
**/*.tsx: Use theLoadingContentcomponent to handle loading states instead of manual loading state management
For text areas, use theInputcomponent withtype='text',autosizeTextareaprop set to true, andregisterPropsfor form integration
Files:
apps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx}: Don't use unnecessary fragments
Don't pass children as props
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 forget key props in iterators and collection literals
Don't define React components inside other components
Don't use event handlers on non-interactive elements
Don't assign to React component props
Don't use bothchildrenanddangerouslySetInnerHTMLprops on the same element
Don't use dangerous JSX props
Don't use Array index in keys
Don't insert comments as text nodes
Don't assign JSX properties multiple times
Don't add extra closing tags for components without children
Use<>...</>instead of<Fragment>...</Fragment>
Watch out for possible "wrong" semicolons inside JSX elements
Make sure void (self-closing) elements don't have children
Don't usetarget="_blank"withoutrel="noopener"
Don't use<img>elements in Next.js projects
Don't use<head>elements in Next.js projects
Files:
apps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
Follow NextJS app router structure with (app) directory
Files:
apps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
apps/web/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (apps/web/CLAUDE.md)
apps/web/**/*.{tsx,jsx}: Follow tailwindcss patterns with prettier-plugin-tailwindcss for class sorting
Prefer functional components with hooks in React
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach in components
Follow consistent naming conventions using PascalCase for components
Use LoadingContent component for async data with loading and error states
Use React Hook Form with Zod validation for form handling
Useresult?.serverErrorwithtoastErrorandtoastSuccessfor error handling in forms
Files:
apps/web/app/(app)/accounts/page.tsxapps/web/app/(app)/[emailAccountId]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
🧠 Learnings (13)
📚 Learning: 2025-07-08T13:14:07.449Z
Learnt from: elie222
Repo: elie222/inbox-zero PR: 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]/calendars/ConnectCalendar.tsxapps/web/app/(app)/[emailAccountId]/calendars/page.tsxapps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx`
Applied to files:
apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-11-25T14:38:56.992Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:56.992Z
Learning: Applies to apps/web/app/(app)/*/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx` with components either colocated in the same folder or in `page.tsx`
Applied to files:
apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/page.tsx : Create new pages at `apps/web/app/(app)/PAGE_NAME/page.tsx`
Applied to files:
apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-11-25T14:38:23.265Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:23.265Z
Learning: Applies to apps/web/app/(app)/**/*.{ts,tsx} : Components for the page are either put in `page.tsx`, or in the `apps/web/app/(app)/PAGE_NAME` folder
Applied to files:
apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : Components for pages are either put in `page.tsx`, or in the `apps/web/app/(app)/PAGE_NAME` folder
Applied to files:
apps/web/app/(app)/[emailAccountId]/calendars/page.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use LoadingContent component for async data with loading and error states
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/components/**/*.tsx : Use `LoadingContent` component to consistently handle loading and error states, passing `loading`, `error`, and `children` props
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:40:13.649Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:13.649Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Use the `LoadingContent` component to handle loading states
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:40:15.063Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-11-25T14:40:15.063Z
Learning: Applies to **/*.tsx : Use the `LoadingContent` component to handle loading states instead of manual loading state management
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:38:18.874Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/page-structure.mdc:0-0
Timestamp: 2025-11-25T14:38:18.874Z
Learning: Applies to apps/web/app/(app)/**/*.tsx : If nested deeply in components, use `swr` to fetch via API instead of loading data directly
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-11-25T14:37:30.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-11-25T14:37:30.660Z
Learning: Applies to apps/web/hooks/use*.ts : For data fetching, prefer using `useSWR` and follow the data-fetching guidelines
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{tsx,jsx} : Use shadcn/ui components when available
Applied to files:
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepConnectCalendar.tsx
🧬 Code graph analysis (2)
apps/web/app/(app)/[emailAccountId]/calendars/page.tsx (1)
apps/web/utils/calendar/constants.ts (1)
CALENDAR_ONBOARDING_RETURN_COOKIE(2-2)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (5)
apps/web/providers/EmailAccountProvider.tsx (1)
useAccount(79-89)apps/web/hooks/useCalendarUpcomingEvents.tsx (1)
useCalendarUpcomingEvents(4-8)apps/web/utils/actions/meeting-briefs.ts (1)
sendBriefAction(40-94)apps/web/components/LoadingContent.tsx (1)
LoadingContent(13-31)apps/web/utils/email.ts (1)
extractDomainFromEmail(73-91)
⏰ 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). (3)
- GitHub Check: cubic · AI code reviewer
- GitHub Check: test
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
apps/web/app/(app)/[emailAccountId]/onboarding-brief/StepSendTestBrief.tsx (1)
19-180: LGTM! Well-structured onboarding component.The implementation follows best practices:
- Uses LoadingContent for async state handling
- Proper error handling with toast notifications
- Semantic HTML with accessible button elements
- Clear visual feedback for loading, selection, and success states
- Good empty state handling with skip option
apps/web/utils/calendar/constants.ts (1)
2-2: LGTM!The constant addition is well-named and follows the existing pattern in the file.
apps/web/app/(app)/accounts/page.tsx (2)
206-219: LGTM!The icon size utility update from
h-4 w-4tosize-4is a cleaner Tailwind convention, and the text change from "Transfer" to "Copy" more accurately describes the functionality.
233-233: LGTM!Consistent icon sizing update.
apps/web/app/(app)/[emailAccountId]/calendars/page.tsx (1)
11-22: LGTM! Path validation properly prevents open redirect.The cookie-based return path logic is well-implemented with proper validation. The code correctly checks that the path is internal (starts with "/" but not "//"), addressing the open redirect concern from previous reviews. The cookie is only read (not deleted) in this server component, which is the appropriate approach.
User description
Note
Introduces a dedicated, 3-step Meeting Briefs onboarding.
onboarding-briefflow:StepConnectCalendar,StepSendTestBrief(pick upcoming event, triggersendBriefAction), andStepReady(pricing summary, Gmail link); rendered viaMeetingBriefsOnboardingContentand page files for app/landingutm_source=briefmymeeting(unlessforce), redirect to/[emailAccountId]/onboarding-briefregisterUtmTrackinghelper wrapsafter()and returns parsed UTM values; adopted in onboarding pagesPricingFrequencyToggleandDiscountBadge, addedfrequencyquery param handling, and typedFrequency; updatedPricing/PriceTierto use themMeeting Briefsitem;SideNavWithTopNavhides sidebars ononboarding-briefroutesWritten by Cursor Bugbot for commit ae28f6d. Configure here.
Generated description
Below is a concise technical summary of the changes proposed in this PR:
graph LR handleCheckout_("handleCheckout"):::added generateCheckoutSession_("generateCheckoutSession"):::modified stripe_("stripe"):::modified SafeError_("SafeError"):::modified trackStripeCustomerCreated_("trackStripeCustomerCreated"):::modified trackStripeCheckoutCreated_("trackStripeCheckoutCreated"):::modified StepReady_("StepReady"):::added PricingFrequencyToggle_("PricingFrequencyToggle"):::added MeetingBriefsOnboardingContent_("MeetingBriefsOnboardingContent"):::added StepConnectCalendar_("StepConnectCalendar"):::added StepSendTestBrief_("StepSendTestBrief"):::added handleCheckout_ -- "Adds priceId param to generateCheckoutSession call." --> generateCheckoutSession_ generateCheckoutSession_ -- "Creates Stripe customers and sessions with tracking." --> stripe_ generateCheckoutSession_ -- "Throws controlled errors for invalid tier or user." --> SafeError_ generateCheckoutSession_ -- "Logs analytics after creating Stripe customer." --> trackStripeCustomerCreated_ generateCheckoutSession_ -- "Logs analytics after creating Stripe checkout session." --> trackStripeCheckoutCreated_ StepReady_ -- "Adds billing frequency toggle for subscription pricing." --> PricingFrequencyToggle_ MeetingBriefsOnboardingContent_ -- "Calls calendar connection step in onboarding." --> StepConnectCalendar_ MeetingBriefsOnboardingContent_ -- "Calls test brief sending step in onboarding." --> StepSendTestBrief_ classDef added stroke:#15AA7A classDef removed stroke:#CD5270 classDef modified stroke:#EDAC4C linkStyle default stroke:#CBD5E1,font-size:13pxIntroduce a dedicated three-step onboarding flow for 'Meeting Briefs', guiding users through calendar connection, sending a test brief, and reviewing subscription options. Integrate this new flow by conditionally redirecting users based on UTM parameters, refactor pricing components for reusability, and update billing configurations to support the new offering.
StepConnectCalendarfor calendar integration,StepSendTestBriefto allow users to send a sample brief, andStepReadywhich presents pricing information and a call to action. The system now redirects users to this specific onboarding path when theutm_sourceisbriefmymeeting, and the navigation layout is adjusted to accommodate these new onboarding routes.Modified files (12)
Latest Contributors(2)
PricingFrequencyToggleandDiscountBadgecomponents. Update thePricingpage to utilize these new components and add specific Stripe price IDs for the 'Brief My Meeting' offering. Modify thegenerateCheckoutSessionActionto support an optionalpriceIdfor more flexible checkout flows. Additionally, introduce a centralizedregisterUtmTrackinghelper to streamline UTM value extraction and storage across onboarding pages.Modified files (5)
Latest Contributors(1)
h-4 w-4tosize-4for consistency and changing the text 'Transfer rules to...' to 'Copy rules to...' in the account options dropdown.Modified files (1)
Latest Contributors(1)