Skip to content

Comments

Staging#951

Merged
MrgSub merged 6 commits intomainfrom
staging
May 12, 2025
Merged

Staging#951
MrgSub merged 6 commits intomainfrom
staging

Conversation

@nizzyabi
Copy link
Collaborator

@nizzyabi nizzyabi commented May 12, 2025

READ CAREFULLY THEN REMOVE

Remove bullet points that are not relevant.

PLEASE REFRAIN FROM USING AI TO WRITE YOUR CODE AND PR DESCRIPTION. IF YOU DO USE AI TO WRITE YOUR CODE PLEASE PROVIDE A DESCRIPTION AND REVIEW IT CAREFULLY. MAKE SURE YOU UNDERSTAND THE CODE YOU ARE SUBMITTING USING AI.

  • Pull requests that do not follow these guidelines will be closed without review or comment.
  • If you use AI to write your PR description your pr will be close without review or comment.
  • If you are unsure about anything, feel free to ask for clarification.

Description

Please provide a clear description of your changes.


Type of Change

Please delete options that are not relevant.

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature with breaking changes)
  • 📝 Documentation update
  • 🎨 UI/UX improvement
  • 🔒 Security enhancement
  • ⚡ Performance improvement

Areas Affected

Please check all that apply:

  • Email Integration (Gmail, IMAP, etc.)
  • User Interface/Experience
  • Authentication/Authorization
  • Data Storage/Management
  • API Endpoints
  • Documentation
  • Testing Infrastructure
  • Development Workflow
  • Deployment/Infrastructure

Testing Done

Describe the tests you've done:

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • Cross-browser testing (if UI changes)
  • Mobile responsiveness verified (if UI changes)

Security Considerations

For changes involving data or authentication:

  • No sensitive data is exposed
  • Authentication checks are in place
  • Input validation is implemented
  • Rate limiting is considered (if applicable)

Checklist

  • I have read the CONTRIBUTING document
  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in complex areas
  • I have updated the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix/feature works
  • All tests pass locally
  • Any dependent changes are merged and published

Additional Notes

Add any other context about the pull request here.

Screenshots/Recordings

Add screenshots or recordings here if applicable.


By submitting this pull request, I confirm that my contribution is made under the terms of the project's license.

Summary by CodeRabbit

  • New Features

    • Added AI-powered email subject generation, allowing users to automatically create concise, professional subject lines based on email content.
    • Introduced a button next to the subject input for generating AI subjects, with a loading indicator during generation.
  • Improvements

    • Enhanced navigation in the email thread list: after moving a thread, the next thread is automatically selected.
    • Updated email composer UI with improved message length indicators and refined content preview styling.
  • Documentation

    • Updated setup instructions to include Cloudflare integration steps and revised Google OAuth redirect URIs for development.

@vercel
Copy link

vercel bot commented May 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
0 ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 12, 2025 4:57pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 12, 2025

Walkthrough

A new AI-powered feature for generating email subject lines based on message content and writing style has been implemented. This includes frontend UI changes, new state management, API hooks, and backend procedures for subject generation using a GPT-4o model. Additional UI and code structure improvements are also included.

Changes

File(s) Change Summary
apps/mail/components/create/email-composer.tsx Added AI subject generation: new state, mutation hook, handler, and UI button; improved subject/body generation logic; updated editor and preview styling; minor CSS tweaks.
apps/mail/components/mail/mail-list.tsx Enhanced thread navigation: added focused index state, next-thread navigation logic, and updated callback to auto-navigate after thread move; minor CSS class order change.
apps/server/src/main.ts Refactored CORS middleware and fetch method; updated WorkerEntrypoint generic; improved type safety and argument passing for request handling.
apps/server/src/trpc/routes/ai/compose.ts Added generateEmailSubject procedure and internal generateSubject function for AI-driven subject generation; uses GPT-4o with style profile; independent from existing compose mutation.
apps/server/src/trpc/routes/ai/index.ts Registered new generateEmailSubject handler in aiRouter; consolidated imports.
.env.example Removed BETTER_AUTH_TRUSTED_ORIGINS variable; updated comments for Google OAuth credentials to reflect new localhost ports.
.github/CONTRIBUTING.md Added step to run bun run cf-install for Cloudflare setup after .env changes in development environment setup instructions.
README.md Updated setup instructions to include running bun run cf-install after .env changes; changed Google OAuth redirect URI to new localhost port; clarified database setup steps.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant EmailComposer (Frontend)
    participant TRPC API (Backend)
    participant AI Model (GPT-4o)

    User->>EmailComposer (Frontend): Click "Generate Subject" button
    EmailComposer (Frontend)->>TRPC API (Backend): generateEmailSubject(message)
    TRPC API (Backend)->>AI Model (GPT-4o): Generate subject with style profile
    AI Model (GPT-4o)-->>TRPC API (Backend): Subject line
    TRPC API (Backend)-->>EmailComposer (Frontend): Subject line
    EmailComposer (Frontend)-->>User: Autofill subject input
Loading

Suggested reviewers

  • ahmetskilinc
  • MrgSub

Poem

In the meadow of code, a new trick appears,
AI crafts subjects, allaying our fears.
With sparkles and spinners, the emails take flight,
GPT pens the titles, concise and polite.
Hopping through threads, the bunny’s delight—
Compose, send, and marvel at features so bright!
🐇✨

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.


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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
apps/server/src/main.ts (1)

79-87: Improved type safety and context handling.

The changes to the class definition and fetch method improve type safety with proper generic typing and ensure the environment and context are correctly passed to the application.

However, the type casting on line 82 could be improved:

-      return routePartykitRequest(request, env as unknown as Record<string, unknown>, {
+      return routePartykitRequest(request, env as Record<string, unknown>, {
apps/mail/components/create/email-composer.tsx (1)

886-888: Add visual feedback for automatic subject generation.

When auto-generating a subject, there's no visual indication to the user that this is happening alongside the message generation. Consider showing a toast notification or other feedback.

if (!subjectInput.trim()) {
+  toast.info('Generating subject and message...');
  await handleGenerateSubject();
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6c38a4c and 805c9db.

📒 Files selected for processing (5)
  • apps/mail/components/create/email-composer.tsx (6 hunks)
  • apps/mail/components/mail/mail-list.tsx (5 hunks)
  • apps/server/src/main.ts (3 hunks)
  • apps/server/src/trpc/routes/ai/compose.ts (2 hunks)
  • apps/server/src/trpc/routes/ai/index.ts (1 hunks)
🔇 Additional comments (12)
apps/server/src/trpc/routes/ai/index.ts (1)

1-9: LGTM! Export changes are correctly integrated.

The new generateEmailSubject procedure has been properly imported and registered in the aiRouter.

apps/server/src/main.ts (2)

8-8: Good cleanup of unused imports.

Removing the unused HonoContext type import helps keep the codebase clean.


21-22: Simplification of CORS callback.

The CORS middleware origin callback has been simplified by removing the unused context parameter.

apps/mail/components/mail/mail-list.tsx (4)

175-176: Improved hook usage with proper destructuring.

Good addition of threads from the useThreads() hook for the thread navigation feature.


184-186: Added state hooks for thread navigation.

The new state hooks are necessary for the thread navigation feature implementation.


236-236: Improved UX with automatic thread navigation after moving.

Adding the call to handleNext after moving a thread provides a better user experience by automatically navigating to the next thread.


611-611: Minor CSS class reordering.

The reordering of CSS classes in the className string doesn't affect functionality.

apps/mail/components/create/email-composer.tsx (5)

107-107: LGTM: New state for tracking subject generation progress.

This looks good, following the same pattern as other loading state management in the component.


112-114: LGTM: New mutation hook for email subject generation.

Well implemented following the existing pattern for TRPC mutation hooks.


693-697: LGTM: Blur effect when showing AI-generated content.

Good implementation using conditional classes with the cn utility function.


926-926: LGTM: Updated button visibility class.

Removed the 'hidden' class to make the button always visible but still responsive with 'md:flex'.


1002-1002: LGTM: Added dark mode styling for content preview.

Added dark mode background support with dark:bg-subtleBlack.

Comment on lines +222 to +261
const generateSubject = async (message: string, styleProfile?: WritingStyleMatrix | null) => {
const parts: string[] = [];

parts.push('# Email Subject Generation Task');
if (styleProfile) {
parts.push('## Style Profile');
parts.push(`\`\`\`json
${JSON.stringify(styleProfile, null, 2)}
\`\`\``);
}

parts.push('## Email Content');
parts.push(escapeXml(message));
parts.push('');
parts.push(
'Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under 100 characters.',
);

const { text } = await generateText({
model: openai('gpt-4o'),
messages: [
{
role: 'system',
content:
'You are an email subject line generator. Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under 100 characters.',
},
{
role: 'user',
content: parts.join('\n\n'),
},
],
maxTokens: 50,
temperature: 0.3,
frequencyPenalty: 0.1,
presencePenalty: 0.1,
maxRetries: 1,
});

return text.trim();
};
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

Improve subject generation function with cleaner structure and error handling.

The generateSubject function has several areas for improvement:

  1. Duplicate instructions in both system and user message
  2. Missing error handling
  3. Hardcoded parameters that should be constants

Apply these improvements:

+const EMAIL_SUBJECT_MAX_LENGTH = 100;
+const SUBJECT_GENERATION_PARAMS = {
+  maxTokens: 50,
+  temperature: 0.3,
+  frequencyPenalty: 0.1,
+  presencePenalty: 0.1,
+  maxRetries: 1,
+};

const generateSubject = async (message: string, styleProfile?: WritingStyleMatrix | null) => {
  const parts: string[] = [];

  parts.push('# Email Subject Generation Task');
  if (styleProfile) {
    parts.push('## Style Profile');
    parts.push(`\`\`\`json
  ${JSON.stringify(styleProfile, null, 2)}
  \`\`\``);
  }

  parts.push('## Email Content');
  parts.push(escapeXml(message));
  parts.push('');
  parts.push(
-    'Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under 100 characters.',
+    `Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under ${EMAIL_SUBJECT_MAX_LENGTH} characters.`,
  );

+  try {
    const { text } = await generateText({
      model: openai('gpt-4o'),
      messages: [
        {
          role: 'system',
          content:
-            'You are an email subject line generator. Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under 100 characters.',
+            `You are an email subject line generator. Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under ${EMAIL_SUBJECT_MAX_LENGTH} characters.`,
        },
        {
          role: 'user',
          content: parts.join('\n\n'),
        },
      ],
-      maxTokens: 50,
-      temperature: 0.3,
-      frequencyPenalty: 0.1,
-      presencePenalty: 0.1,
-      maxRetries: 1,
+      ...SUBJECT_GENERATION_PARAMS,
    });

    return text.trim();
+  } catch (error) {
+    console.error('Failed to generate subject:', error);
+    throw error;
+  }
};
📝 Committable suggestion

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

Suggested change
const generateSubject = async (message: string, styleProfile?: WritingStyleMatrix | null) => {
const parts: string[] = [];
parts.push('# Email Subject Generation Task');
if (styleProfile) {
parts.push('## Style Profile');
parts.push(`\`\`\`json
${JSON.stringify(styleProfile, null, 2)}
\`\`\``);
}
parts.push('## Email Content');
parts.push(escapeXml(message));
parts.push('');
parts.push(
'Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under 100 characters.',
);
const { text } = await generateText({
model: openai('gpt-4o'),
messages: [
{
role: 'system',
content:
'You are an email subject line generator. Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under 100 characters.',
},
{
role: 'user',
content: parts.join('\n\n'),
},
],
maxTokens: 50,
temperature: 0.3,
frequencyPenalty: 0.1,
presencePenalty: 0.1,
maxRetries: 1,
});
return text.trim();
};
const EMAIL_SUBJECT_MAX_LENGTH = 100;
const SUBJECT_GENERATION_PARAMS = {
maxTokens: 50,
temperature: 0.3,
frequencyPenalty: 0.1,
presencePenalty: 0.1,
maxRetries: 1,
};
const generateSubject = async (message: string, styleProfile?: WritingStyleMatrix | null) => {
const parts: string[] = [];
parts.push('# Email Subject Generation Task');
if (styleProfile) {
parts.push('## Style Profile');
parts.push(`\`\`\`json
${JSON.stringify(styleProfile, null, 2)}
\`\`\``);
}
parts.push('## Email Content');
parts.push(escapeXml(message));
parts.push('');
parts.push(
`Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under ${EMAIL_SUBJECT_MAX_LENGTH} characters.`,
);
try {
const { text } = await generateText({
model: openai('gpt-4o'),
messages: [
{
role: 'system',
content: `You are an email subject line generator. Generate a concise, clear subject line that summarizes the main point of the email. The subject should be professional and under ${EMAIL_SUBJECT_MAX_LENGTH} characters.`,
},
{
role: 'user',
content: parts.join('\n\n'),
},
],
...SUBJECT_GENERATION_PARAMS,
});
return text.trim();
} catch (error) {
console.error('Failed to generate subject:', error);
throw error;
}
};

Comment on lines +108 to +128
export const generateEmailSubject = activeConnectionProcedure
.input(
z.object({
message: z.string(),
}),
)
.mutation(async ({ ctx, input }) => {
const { activeConnection } = ctx;
const { message } = input;

const writingStyleMatrix = await getWritingStyleMatrixForConnectionId({
connectionId: activeConnection.id,
c: ctx.c,
});

const subject = await generateSubject(message, writingStyleMatrix?.style as WritingStyleMatrix);

return {
subject,
};
});
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

Missing error handling for AI service failures.

The new generateEmailSubject procedure doesn't include any error handling if the AI model fails to generate a subject or if the service times out.

Add a try/catch block to gracefully handle errors:

export const generateEmailSubject = activeConnectionProcedure
  .input(
    z.object({
      message: z.string(),
    }),
  )
  .mutation(async ({ ctx, input }) => {
    const { activeConnection } = ctx;
    const { message } = input;

    const writingStyleMatrix = await getWritingStyleMatrixForConnectionId({
      connectionId: activeConnection.id,
      c: ctx.c,
    });

+   try {
      const subject = await generateSubject(message, writingStyleMatrix?.style as WritingStyleMatrix);
    
      return {
        subject,
      };
+   } catch (error) {
+     console.error('Error generating email subject:', error);
+     throw new Error('Failed to generate email subject. Please try again later.');
+   }
  });
📝 Committable suggestion

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

Suggested change
export const generateEmailSubject = activeConnectionProcedure
.input(
z.object({
message: z.string(),
}),
)
.mutation(async ({ ctx, input }) => {
const { activeConnection } = ctx;
const { message } = input;
const writingStyleMatrix = await getWritingStyleMatrixForConnectionId({
connectionId: activeConnection.id,
c: ctx.c,
});
const subject = await generateSubject(message, writingStyleMatrix?.style as WritingStyleMatrix);
return {
subject,
};
});
export const generateEmailSubject = activeConnectionProcedure
.input(
z.object({
message: z.string(),
}),
)
.mutation(async ({ ctx, input }) => {
const { activeConnection } = ctx;
const { message } = input;
const writingStyleMatrix = await getWritingStyleMatrixForConnectionId({
connectionId: activeConnection.id,
c: ctx.c,
});
try {
const subject = await generateSubject(
message,
writingStyleMatrix?.style as WritingStyleMatrix,
);
return {
subject,
};
} catch (error) {
console.error('Error generating email subject:', error);
throw new Error('Failed to generate email subject. Please try again later.');
}
});

Comment on lines +212 to +225
const handleNext = useCallback(
(id: string) => {
if (!id || !threads.length || focusedIndex === null) return setThreadId(null);
if (focusedIndex < threads.length - 1) {
const nextThread = threads[focusedIndex];
if (nextThread) {
setThreadId(nextThread.id);
setActiveReplyId(null);
setFocusedIndex(focusedIndex);
}
}
},
[threads, id, focusedIndex],
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the thread navigation logic in handleNext function.

The handleNext function has a logic issue - it's not actually navigating to the next thread, but instead using the current thread position.

Apply this fix:

const handleNext = useCallback(
  (id: string) => {
    if (!id || !threads.length || focusedIndex === null) return setThreadId(null);
    if (focusedIndex < threads.length - 1) {
-      const nextThread = threads[focusedIndex];
+      const nextThread = threads[focusedIndex + 1];
      if (nextThread) {
        setThreadId(nextThread.id);
        setActiveReplyId(null);
-        setFocusedIndex(focusedIndex);
+        setFocusedIndex(focusedIndex + 1);
      }
    }
  },
-  [threads, id, focusedIndex],
+  [threads, focusedIndex, setThreadId, setActiveReplyId, setFocusedIndex],
);
📝 Committable suggestion

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

Suggested change
const handleNext = useCallback(
(id: string) => {
if (!id || !threads.length || focusedIndex === null) return setThreadId(null);
if (focusedIndex < threads.length - 1) {
const nextThread = threads[focusedIndex];
if (nextThread) {
setThreadId(nextThread.id);
setActiveReplyId(null);
setFocusedIndex(focusedIndex);
}
}
},
[threads, id, focusedIndex],
);
const handleNext = useCallback(
(id: string) => {
if (!id || !threads.length || focusedIndex === null) return setThreadId(null);
if (focusedIndex < threads.length - 1) {
const nextThread = threads[focusedIndex + 1];
if (nextThread) {
setThreadId(nextThread.id);
setActiveReplyId(null);
setFocusedIndex(focusedIndex + 1);
}
}
},
[threads, focusedIndex, setThreadId, setActiveReplyId, setFocusedIndex],
);

Comment on lines +674 to +688
<button
className=""
onClick={handleGenerateSubject}
disabled={isLoading || isGeneratingSubject}
>
<div className="flex items-center justify-center gap-2.5 pl-0.5">
<div className="flex h-5 items-center justify-center gap-1 rounded-sm">
{isGeneratingSubject ? (
<Loader className="h-3.5 w-3.5 animate-spin fill-black dark:fill-white" />
) : (
<Sparkles className="h-3.5 w-3.5 fill-black dark:fill-white" />
)}
</div>
</div>
</button>
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

Improve button accessibility and styling.

The button has an empty className prop and lacks accessibility attributes. Add an aria-label and tooltip to explain the button's purpose for better user experience.

<button
-  className=""
+  className="focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#8B5CF6] rounded-md"
  onClick={handleGenerateSubject}
  disabled={isLoading || isGeneratingSubject}
+  aria-label="Generate email subject using AI"
>
  <div className="flex items-center justify-center gap-2.5 pl-0.5">
    <div className="flex h-5 items-center justify-center gap-1 rounded-sm">
      {isGeneratingSubject ? (
        <Loader className="h-3.5 w-3.5 animate-spin fill-black dark:fill-white" />
      ) : (
        <Sparkles className="h-3.5 w-3.5 fill-black dark:fill-white" />
      )}
    </div>
  </div>
</button>

Consider wrapping this button in a Tooltip component like other action buttons in this component:

<Tooltip>
  <TooltipTrigger asChild>
    <button>
      {/* button content */}
    </button>
  </TooltipTrigger>
  <TooltipContent>
    <p>Generate AI subject</p>
  </TooltipContent>
</Tooltip>

Comment on lines +361 to +366
const handleGenerateSubject = async () => {
setIsGeneratingSubject(true);
const { subject } = await generateEmailSubject({ message: editor.getText() });
setValue('subject', subject);
setIsGeneratingSubject(false);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling to prevent UI from getting stuck.

The function lacks error handling. If the API call fails, isGeneratingSubject will remain true, leaving the UI in a perpetual loading state.

const handleGenerateSubject = async () => {
  setIsGeneratingSubject(true);
-  const { subject } = await generateEmailSubject({ message: editor.getText() });
-  setValue('subject', subject);
-  setIsGeneratingSubject(false);
+  try {
+    const { subject } = await generateEmailSubject({ message: editor.getText() });
+    setValue('subject', subject);
+    toast.success('Subject generated successfully');
+  } catch (error) {
+    console.error('Error generating subject:', error);
+    toast.error('Failed to generate subject');
+  } finally {
+    setIsGeneratingSubject(false);
+  }
};
📝 Committable suggestion

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

Suggested change
const handleGenerateSubject = async () => {
setIsGeneratingSubject(true);
const { subject } = await generateEmailSubject({ message: editor.getText() });
setValue('subject', subject);
setIsGeneratingSubject(false);
};
const handleGenerateSubject = async () => {
setIsGeneratingSubject(true);
try {
const { subject } = await generateEmailSubject({ message: editor.getText() });
setValue('subject', subject);
toast.success('Subject generated successfully');
} catch (error) {
console.error('Error generating subject:', error);
toast.error('Failed to generate subject');
} finally {
setIsGeneratingSubject(false);
}
};

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
README.md (2)

83-83: Improve phrasing and grammar for Cloudflare setup instruction.

The current line reads:

- Setup cloudflare with `bun run cf-install`, you will need to run this everytime there is a `.env` change

Suggested rewrite for clarity, correctness, and consistency (capitalize “Cloudflare”, split “every time”, and reference “the .env file”):

-   - Setup cloudflare with `bun run cf-install`, you will need to run this everytime there is a `.env` change
+   - Set up Cloudflare integration by running `bun run cf-install` after any change to the `.env` file to sync environment variables.

214-214: Fix grammar in environment sync instruction.

The current sentence has a missing article and an incorrect verb form:

Make sure your database connection string is in `.env` file. And you have ran `bun run cf-install` to sync the latest env.

Please apply this diff for grammatical accuracy and clarity:

-   Make sure your database connection string is in `.env` file. And you have ran `bun run cf-install` to sync the latest env.
+   Make sure your database connection string is in the `.env` file, and you have run `bun run cf-install` to sync the latest environment variables.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~214-~214: You might be missing the article “the” here.
Context: ...e your database connection string is in .env file. And you have ran `bun run cf...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[grammar] ~214-~214: It appears that the past participle should be used here.
Context: ... string is in .env file. And you have ran bun run cf-install to sync the latest...

(HAVE_PART_AGREEMENT)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 805c9db and badf925.

📒 Files selected for processing (3)
  • .env.example (1 hunks)
  • .github/CONTRIBUTING.md (1 hunks)
  • README.md (3 hunks)
✅ Files skipped from review due to trivial changes (2)
  • .env.example
  • .github/CONTRIBUTING.md
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~214-~214: You might be missing the article “the” here.
Context: ...e your database connection string is in .env file. And you have ran `bun run cf...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[grammar] ~214-~214: It appears that the past participle should be used here.
Context: ... string is in .env file. And you have ran bun run cf-install to sync the latest...

(HAVE_PART_AGREEMENT)

🔇 Additional comments (1)
README.md (1)

152-152: Confirm OAuth redirect URI update across all configurations.

You’ve updated the development callback URI to:

- `http://localhost:8787/api/auth/callback/google`

Please verify that this change is reflected consistently in:

  • .env.example
  • NextAuth (or Better Auth) configuration files
  • Any CI/CD or deployment workflows (e.g., GitHub Actions secrets)

@MrgSub MrgSub merged commit 8ce4499 into main May 12, 2025
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jun 3, 2025
34 tasks
@coderabbitai coderabbitai bot mentioned this pull request Jun 19, 2025
11 tasks
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.

4 participants