Skip to content

Fix Digest emails#547

Merged
elie222 merged 2 commits intoelie222:mainfrom
edulelis:digest-emails-v2
Jul 8, 2025
Merged

Fix Digest emails#547
elie222 merged 2 commits intoelie222:mainfrom
edulelis:digest-emails-v2

Conversation

@edulelis
Copy link
Collaborator

@edulelis edulelis commented Jul 7, 2025

Realigning digest counts as image below
Screenshot 2025-07-06 at 16 31 34

Summary by CodeRabbit

  • New Features
    • Onboarding now ensures a default digest schedule is set for users, with a weekly interval on Mondays at 11 AM in the user's timezone.
  • Bug Fixes
    • Improved error handling during onboarding to prevent progress if saving categories or setting the schedule fails.
  • Style
    • Added consistent left margin to email count badges in the digest category grid for improved visual alignment.
  • Documentation
    • Refined AI prompt instructions to enforce concise, precise responses and valid JSON output.

@vercel
Copy link

vercel bot commented Jul 7, 2025

@edulelis is attempting to deploy a commit to the Inbox Zero Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 7, 2025

Walkthrough

The changes introduce logic to ensure a default digest schedule is created for users during onboarding, including a new server action for this purpose. The onboarding flow now checks and sets the digest schedule alongside categories. Minor prompt refinements and a UI spacing adjustment for email category badges are also included.

Changes

File(s) Change Summary
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx Ensures default digest schedule on onboarding; updates control flow to require both categories and schedule to be set before completion.
apps/web/utils/actions/settings.ts Adds ensureDefaultDigestScheduleAction server action to create a default digest schedule if none exists.
apps/web/utils/ai/choose-rule/ai-choose-rule.ts Refines AI prompt to enforce concise, precise responses and valid JSON output.
packages/resend/emails/digest.tsx Adds 8px left margin to category count badges in the digest email category grid.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant OnboardingPage
    participant ServerActions

    User->>OnboardingPage: Complete digest categories selection
    OnboardingPage->>ServerActions: updateDigestCategoriesAction
    alt Success
        OnboardingPage->>ServerActions: ensureDefaultDigestScheduleAction
        alt Schedule exists or created
            OnboardingPage->>User: Show success, complete onboarding
        else Schedule creation fails
            OnboardingPage->>User: Show error toast
        end
    else Categories save fails
        OnboardingPage->>User: Show error toast
    end
Loading

Possibly related PRs

  • feat: Digest e-mails #478: Extends category setup to support digest toggling per category, modifying onboarding components and actions related to digest settings.

Poem

A rabbit hops with code so neat,
Ensuring digests never skip a beat.
With schedules set and badges spaced,
Onboarding flows are now well-paced.
Prompts are sharp, the UI refined—
Another hop ahead, with peace of mind!
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx

Oops! Something went wrong! :(

ESLint: 9.28.0

ESLint couldn't find an eslint.config.(js|mjs|cjs) file.

From ESLint v9.0.0, the default configuration file is now eslint.config.js.
If you are using a .eslintrc.* file, please follow the migration guide
to update your configuration file to the new format:

https://eslint.org/docs/latest/use/configure/migration-guide

If you still have problems after following the migration guide, please stop by
https://eslint.org/chat/help to chat with the team.

apps/web/utils/actions/settings.ts

Oops! Something went wrong! :(

ESLint: 9.28.0

ESLint couldn't find an eslint.config.(js|mjs|cjs) file.

From ESLint v9.0.0, the default configuration file is now eslint.config.js.
If you are using a .eslintrc.* file, please follow the migration guide
to update your configuration file to the new format:

https://eslint.org/docs/latest/use/configure/migration-guide

If you still have problems after following the migration guide, please stop by
https://eslint.org/chat/help to chat with the team.

apps/web/utils/ai/choose-rule/ai-choose-rule.ts

Oops! Something went wrong! :(

ESLint: 9.28.0

ESLint couldn't find an eslint.config.(js|mjs|cjs) file.

From ESLint v9.0.0, the default configuration file is now eslint.config.js.
If you are using a .eslintrc.* file, please follow the migration guide
to update your configuration file to the new format:

https://eslint.org/docs/latest/use/configure/migration-guide

If you still have problems after following the migration guide, please stop by
https://eslint.org/chat/help to chat with the team.

  • 1 others
✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

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

@edulelis edulelis marked this pull request as ready for review July 7, 2025 10:53
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 053574e and 697a397.

📒 Files selected for processing (4)
  • apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx (3 hunks)
  • apps/web/utils/actions/settings.ts (2 hunks)
  • apps/web/utils/ai/choose-rule/ai-choose-rule.ts (2 hunks)
  • packages/resend/emails/digest.tsx (5 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
`apps/web/**/*.{ts,tsx}`: Use TypeScript with strict null checks Path aliases: U...

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Path aliases: Use @/ for imports from project root
Use proper error handling with try/catch blocks
Format code with Prettier

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

List of files the instruction was applied to:

  • apps/web/utils/ai/choose-rule/ai-choose-rule.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx
  • apps/web/utils/actions/settings.ts
`**/*.{ts,tsx}`: Define validation schemas using Zod Apply the same validation in both client and server Use descriptive error messages

**/*.{ts,tsx}: Define validation schemas using Zod
Apply the same validation in both client and server
Use descriptive error messages

📄 Source: CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)

List of files the instruction was applied to:

  • apps/web/utils/ai/choose-rule/ai-choose-rule.ts
  • apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx
  • packages/resend/emails/digest.tsx
  • apps/web/utils/actions/settings.ts
`apps/web/app/**/*`: NextJS app router structure with (app) directory

apps/web/app/**/*: NextJS app router structure with (app) directory

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

List of files the instruction was applied to:

  • apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx
`apps/web/**/*.tsx`: Follow tailwindcss patterns with prettier-plugin-tailwindcs...

apps/web/**/*.tsx: Follow tailwindcss patterns with prettier-plugin-tailwindcss
Prefer functional components with hooks
Use shadcn/ui components when available
Ensure responsive design with mobile-first approach
Follow consistent naming conventions (PascalCase for components)
Use LoadingContent component for async data

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

List of files the instruction was applied to:

  • apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx
`**/*.tsx`: For API GET requests to server, use the `swr` package Use `result?.serverError` with `toastError` and `toastSuccess` for error handling; success toast is optional

**/*.tsx: For API GET requests to server, use the swr package
Use result?.serverError with toastError and toastSuccess for error handling; success toast is optional

📄 Source: CodeRabbit Inference Engine (.cursor/rules/data-fetching.mdc)

List of files the instruction was applied to:

  • apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx
  • packages/resend/emails/digest.tsx
`**/*.tsx`: Use React Hook Form with Zod for validation Validate form inputs before submission Show validation errors inline next to form fields

**/*.tsx: Use React Hook Form with Zod for validation
Validate form inputs before submission
Show validation errors inline next to form fields

📄 Source: CodeRabbit Inference Engine (.cursor/rules/form-handling.mdc)

List of files the instruction was applied to:

  • apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx
  • packages/resend/emails/digest.tsx
🧠 Learnings (3)
apps/web/utils/ai/choose-rule/ai-choose-rule.ts (2)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/index.mdc:0-0
Timestamp: 2025-06-23T12:26:22.732Z
Learning: Clearly document the purpose and scope of each rule file to help developers quickly understand where to find relevant guidance.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/cursor-rules.mdc:0-0
Timestamp: 2025-07-03T12:02:24.598Z
Learning: Applies to .cursor/rules/*.mdc : Make Cursor rule file names descriptive of the rule's purpose
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx (7)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/hooks.mdc:0-0
Timestamp: 2025-06-23T12:26:16.769Z
Learning: Custom React hooks should encapsulate reusable stateful logic, especially for data fetching or complex UI interactions.
Learnt from: aryanprince
PR: elie222/inbox-zero#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`.
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Prefer functional components with hooks
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-06-23T12:26:59.468Z
Learning: For components with onClick handlers in Next.js App Router, ensure they are client components by including the 'use client' directive at the top of the file.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-03T12:02:38.024Z
Learning: For mutating data, use Next.js server actions
Learnt from: CR
PR: elie222/inbox-zero#0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:02:16.137Z
Learning: Applies to apps/web/**/*.tsx : Use shadcn/ui components when available
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-06-23T12:27:33.499Z
Learning: For form text inputs in React using Shadcn UI, use the `Input` component with `registerProps` from a form library (such as react-hook-form) and pass any validation errors to the `error` prop.
apps/web/utils/actions/settings.ts (7)
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Input validation schemas for server actions should be defined using Zod in dedicated .validation.ts files, which can be reused on the client for form validation.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: Sentry instrumentation for server actions is automatically applied via withServerActionInstrumentation in the safe action clients, and meaningful action names should be provided using the .metadata({ name: "actionName" }) method.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: In Next.js projects, server actions should be implemented using the next-safe-action library to ensure type safety, input validation, context management, and centralized error handling.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/data-fetching.mdc:0-0
Timestamp: 2025-07-03T12:02:38.024Z
Learning: For mutating data, use Next.js server actions
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-06-23T12:27:23.938Z
Learning: The next-safe-action library provides different clients for context management: actionClientUser for authenticated user context, actionClient for user plus resource-specific context (like emailAccountId), and adminActionClient for admin-restricted actions.
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.{ts,tsx} : Define validation schemas using Zod
Learnt from: CR
PR: elie222/inbox-zero#0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-07-03T12:02:53.001Z
Learning: Applies to **/*.tsx : Use React Hook Form with Zod for validation
🧬 Code Graph Analysis (2)
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx (3)
apps/web/utils/actions/settings.ts (2)
  • ensureDefaultDigestScheduleAction (200-237)
  • updateDigestScheduleAction (54-104)
apps/web/utils/cookies.ts (2)
  • markOnboardingAsCompleted (4-6)
  • ASSISTANT_ONBOARDING_COOKIE (1-1)
apps/web/utils/path.ts (1)
  • prefixPath (1-4)
apps/web/utils/actions/settings.ts (3)
apps/web/utils/actions/safe-action.ts (1)
  • actionClient (43-73)
apps/web/utils/schedule.ts (1)
  • calculateNextScheduleDate (52-150)
apps/web/utils/error.ts (1)
  • SafeError (83-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). (2)
  • GitHub Check: Static Code Analysis Js
  • GitHub Check: Jit Security
🔇 Additional comments (6)
apps/web/utils/actions/settings.ts (1)

200-237: Default digest schedule bitmask verified and correct

The maskFor utility maps JavaScript days (0 = Sunday … 6 = Saturday) to bitmasks via 1 << (6 - jsDay). Calling maskFor(1) yields 1 << 5, so using 1 << (6 - 1) for Monday is accurate. No changes needed—LGTM!

packages/resend/emails/digest.tsx (1)

207-207: LGTM! Consistent margin adjustment improves badge alignment.

The uniform application of ml-[8px] across all category count scenarios will improve the visual alignment of digest count badges, which aligns with the PR objective to fix digest email alignment.

Also applies to: 241-241, 264-264, 299-299, 321-321

apps/web/utils/ai/choose-rule/ai-choose-rule.ts (2)

33-35: LGTM! Improved prompt instructions for better AI responses.

The additional priority rules will help ensure more concise and accurate AI responses by requiring exact rule name matching and avoiding repetitive explanations.


67-67: LGTM! Better specification of expected output format.

Clarifying "valid JSON object" instead of just "JSON object" helps set clearer expectations for the AI response format.

apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx (2)

9-13: LGTM! Proper imports for the new digest schedule functionality.

The imports correctly include both actions needed for the enhanced onboarding flow.


82-119: LGTM! Well-structured sequential updates with proper error handling.

The enhanced handleFinish function correctly coordinates both digest categories and schedule updates. The error handling with early returns ensures that onboarding only proceeds when both operations succeed, which is the correct behavior.

The schedule configuration (weekly on Monday at 11 AM) is consistent with the default created in the useEffect and server action.

Comment on lines +60 to +65
useEffect(() => {
// Ensure user has a digest schedule entry when they visit this page, otherwise the digest is not sent
const timeOfDay = new Date();
timeOfDay.setHours(11, 0, 0, 0); // 11 AM in user's timezone
ensureDefaultDigestScheduleAction(emailAccountId, { timeOfDay });
}, [emailAccountId]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for the default schedule creation.

The useEffect lacks error handling for ensureDefaultDigestScheduleAction. While this action is designed to be safe, adding error handling would improve robustness.

  useEffect(() => {
    // Ensure user has a digest schedule entry when they visit this page, otherwise the digest is not sent
    const timeOfDay = new Date();
    timeOfDay.setHours(11, 0, 0, 0); // 11 AM in user's timezone
-   ensureDefaultDigestScheduleAction(emailAccountId, { timeOfDay });
+   ensureDefaultDigestScheduleAction(emailAccountId, { timeOfDay }).catch(
+     (error) => {
+       console.error("Failed to ensure default digest schedule:", error);
+       // Non-blocking error - user can still proceed with onboarding
+     }
+   );
  }, [emailAccountId]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
// Ensure user has a digest schedule entry when they visit this page, otherwise the digest is not sent
const timeOfDay = new Date();
timeOfDay.setHours(11, 0, 0, 0); // 11 AM in user's timezone
ensureDefaultDigestScheduleAction(emailAccountId, { timeOfDay });
}, [emailAccountId]);
useEffect(() => {
// Ensure user has a digest schedule entry when they visit this page, otherwise the digest is not sent
const timeOfDay = new Date();
timeOfDay.setHours(11, 0, 0, 0); // 11 AM in user's timezone
ensureDefaultDigestScheduleAction(emailAccountId, { timeOfDay }).catch(
(error) => {
console.error("Failed to ensure default digest schedule:", error);
// Non-blocking error - user can still proceed with onboarding
}
);
}, [emailAccountId]);
🤖 Prompt for AI Agents
In
apps/web/app/(app)/[emailAccountId]/assistant/onboarding/digest-frequency/page.tsx
around lines 60 to 65, the useEffect calls ensureDefaultDigestScheduleAction
without error handling. Wrap the call in a try-catch block or handle the promise
rejection to catch any errors during the default schedule creation, and log or
handle the error appropriately to improve robustness.

@elie222 elie222 merged commit 8a69d20 into elie222:main Jul 8, 2025
8 of 9 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jul 11, 2025
@edulelis edulelis deleted the digest-emails-v2 branch July 24, 2025 18:15
@coderabbitai coderabbitai bot mentioned this pull request Aug 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments