Skip to content

Add CI checks for the backend/email workspace#13

Open
duck-master wants to merge 11 commits intosipec:mainfrom
duck-master:add-backend-email-ci-checks
Open

Add CI checks for the backend/email workspace#13
duck-master wants to merge 11 commits intosipec:mainfrom
duck-master:add-backend-email-ci-checks

Conversation

@duck-master
Copy link
Copy Markdown

@duck-master duck-master commented Aug 7, 2025

This is my third PR in the series.

For some reason, unsubscribeUrl (a property of three different interfaces, namely NewEndorsementEmailProps, NewMatchEmailProps, and NewMessageEmailProps) is never, ever used. I eliminated references to it by naming the input to each function, thus appeasing ESLint for the time being. However, since lots of people (including me!) get tons of email that we never read, a working unsubscribe feature would actually be really useful.

It might be cleaner too to also change all three properties to be types instead of interfaces. That way, we can do object destructuring instead of having to use . to access a property every single time.

Summary by CodeRabbit

  • Chores

    • Added a CI workflow for the backend email service to run linting, formatting checks, and type checks.
    • Added ESLint config and tooling, updated package dependencies, and a Prettier ignore for generated files.
  • Refactor

    • Converted email components to accept a single props object and updated helper calls accordingly.
    • Removed/disabled unsubscribe link usage and commented related imports/styles in email templates.
  • Style

    • Added a newline at the end of one email function file.

@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 7, 2025

@duck-master is attempting to deploy a commit to the polylove Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 7, 2025

Walkthrough

Adds CI workflow and lint/format tooling for the backend/email workspace, removes unsubscribeUrl usage from email components and helpers, and refactors several email components to accept a single props object; also adds Prettier ignore and ESLint config plus related package deps.

Changes

Cohort / File(s) Change Summary
CI Workflow Configuration
.github/workflows/ci-backend-email.yml
Adds a GitHub Actions workflow to run ESLint, Prettier, and TypeScript checks for changes under backend/email.
Prettier Ignore
backend/email/.prettierignore
Adds .prettierignore to exclude lib/**/* from Prettier formatting.
ESLint Config & deps
backend/email/eslint.config.mjs,
backend/email/package.json
Adds an ESLint configuration file and adds eslint, @eslint/js, globals, and typescript-eslint packages to package.json.
Email Component Refactors
backend/email/emails/new-endorsement.tsx,
backend/email/emails/new-match.tsx,
backend/email/emails/new-message.tsx
Change component signatures to accept a single props object; remove/comment-out unsubscribeUrl and related footer/link styling; adjust internal prop access and local variables.
Email Helpers
backend/email/emails/functions/helpers.tsx
Stop retrieving/passing unsubscribeUrl from notification destinations; remove it when calling sendEmail.
Minor / Formatting
backend/email/emails/functions/send-test-email.ts
Adds a trailing newline (formatting-only).

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant GH as GitHub
    participant CI as CI Workflow
    participant Repo as Repository
    participant ESL as ESLint
    participant PR as Prettier
    participant TS as TypeScript

    Dev->>GH: Push or open PR touching backend/email/*
    GH->>CI: Trigger ci-backend-email.yml
    CI->>Repo: set working-directory: backend/email
    CI->>ESL: run eslint
    CI->>PR: run prettier --check
    CI->>TS: run tsc -b && tsc --noEmit --strict
    ESL-->>CI: lint results
    PR-->>CI: format results
    TS-->>CI: typecheck results
    CI-->>GH: report status checks
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Poem

A rabbit hops through code at night,
Linting crumbs by candlelight.
Props bundled snug, unsubscribe gone—
CI hums softly on and on.
I twitch my nose, then bound away,
Morning brings a cleaner day. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

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

Other keywords and placeholders

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

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

Status, Documentation and Community

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

Copy link
Copy Markdown

@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: 2

🔭 Outside diff range comments (3)
backend/email/emails/new-endorsement.tsx (1)

19-24: Remove unused unsubscribeUrl property from interface.

The unsubscribeUrl property is defined in the interface but never used in the component implementation, creating dead code.

 interface NewEndorsementEmailProps {
   fromUser: User
   onUser: User
   endorsementText: string
-  unsubscribeUrl: string
 }
backend/email/emails/new-match.tsx (1)

19-24: Remove unused unsubscribeUrl property from interface.

Same issue as in new-endorsement.tsx - the unsubscribeUrl property is defined but never used.

 interface NewMatchEmailProps {
   onUser: User
   matchedWithUser: User
   matchedLover: LoverRow
-  unsubscribeUrl: string
 }
backend/email/emails/new-message.tsx (1)

80-86: Clean up incomplete footer text.

The footer has an incomplete sentence due to the commented out unsubscribe link. Either implement the unsubscribe functionality or provide a complete sentence.

           <Text style={footerText}>
-            This e-mail has been sent to {name},{' '}
-            {/* <Link href={unsubscribeUrl} style={{ color: 'inherit', textDecoration: 'none' }}>
-              click here to unsubscribe from this type of notification
-            </Link>
-            . */}
+            This e-mail has been sent to {name}.
           </Text>
🧹 Nitpick comments (9)
backend/email/emails/new-endorsement.tsx (3)

9-9: Unused import should be removed entirely.

The commented-out Link import should be removed completely rather than left as a comment, since it's not being used anywhere in the component.

-  //Link,

26-31: Consider reverting to parameter destructuring for cleaner code.

The current approach makes the code more verbose than necessary. React components typically use parameter destructuring for cleaner, more readable code.

-export const NewEndorsementEmail = (
-  newEndorsementEmailProps: NewEndorsementEmailProps
-) => {
-  const onUser: User = newEndorsementEmailProps.onUser
-  const fromUser: User = newEndorsementEmailProps.fromUser
-  const name: string = onUser.name.split(' ')[0]
+export const NewEndorsementEmail = ({
+  fromUser,
+  onUser,
+  endorsementText,
+}: NewEndorsementEmailProps) => {
+  const name = onUser.name.split(' ')[0]

The explicit type annotations are also unnecessary as TypeScript can infer these types from the interface.


176-179: Remove commented code entirely.

Commented-out code should be removed rather than left in the codebase, as version control preserves the history.

-/*const footerLink = {
-  color: 'inherit',
-  textDecoration: 'none',
-}*/
backend/email/emails/new-match.tsx (3)

8-8: Remove unused Link import.

The Link import is no longer used since the unsubscribe footer link is commented out. Unlike new-endorsement.tsx where it was commented out, this should be removed entirely for consistency.

-  Link,

26-31: Consider reverting to parameter destructuring for consistency.

Same verbose pattern as new-endorsement.tsx. Consider using parameter destructuring for cleaner, more idiomatic React code.

-export const NewMatchEmail = (newMatchEmailProps: NewMatchEmailProps) => {
-  const name: string = newMatchEmailProps.onUser.name.split(' ')[0]
-  const matchedWithUser: User = newMatchEmailProps.matchedWithUser
-  const matchedLover: LoverRow = newMatchEmailProps.matchedLover
-  const userImgSrc: string = getLoveOgImageUrl(matchedWithUser, matchedLover)
-  const userUrl: string = `https://${DOMAIN}/${matchedWithUser.username}`
+export const NewMatchEmail = ({
+  onUser,
+  matchedWithUser,
+  matchedLover,
+}: NewMatchEmailProps) => {
+  const name = onUser.name.split(' ')[0]
+  const userImgSrc = getLoveOgImageUrl(matchedWithUser, matchedLover)
+  const userUrl = `https://${DOMAIN}/${matchedWithUser.username}`

159-162: Remove commented code entirely.

Consistent with the recommendation for new-endorsement.tsx, remove commented-out code rather than leaving it in the codebase.

-/*const footerLink = {
-  color: 'inherit',
-  textDecoration: 'none',
-}*/
backend/email/emails/new-message.tsx (2)

32-40: Consider the trade-offs of this refactoring approach.

The change from destructured parameters to a props object makes the code more verbose without clear benefits. TypeScript already provides excellent IntelliSense and type checking with destructured parameters.

Consider reverting to destructured parameters for better readability:

-export const NewMessageEmail = (newMessageEmailProps: NewMessageEmailProps) => {
-  const name: string = newMessageEmailProps.toUser.name.split(' ')[0]
-  const creatorName: string = newMessageEmailProps.fromUser.name
-  const channelId: number = newMessageEmailProps.channelId
-  const messagesUrl: string = `https://${DOMAIN}/messages/${channelId}`
-  const userImgSrc: string = getLoveOgImageUrl(
-    newMessageEmailProps.fromUser,
-    newMessageEmailProps.fromUserLover
-  )
+export const NewMessageEmail = ({
+  fromUser,
+  fromUserLover,
+  toUser,
+  channelId,
+}: NewMessageEmailProps) => {
+  const name = toUser.name.split(' ')[0]
+  const creatorName = fromUser.name
+  const messagesUrl = `https://${DOMAIN}/messages/${channelId}`
+  const userImgSrc = getLoveOgImageUrl(fromUser, fromUserLover)

The explicit type annotations are also unnecessary since TypeScript can infer these types from the interface properties.


18-18: Remove commented out import.

Remove the commented out sinclairLover import instead of keeping it as a comment.

   jamesLover,
   jamesUser,
-  //sinclairLover,
   sinclairUser,
.github/workflows/ci-backend-email.yml (1)

16-50: Consider optimizing CI jobs for better performance and reliability.

The jobs are well-structured but could benefit from some optimizations:

  1. Specify Node.js version for consistency:
       - uses: actions/setup-node@v4
+        with:
+          node-version: '18'
  1. Add dependency caching to speed up builds:
       - uses: actions/setup-node@v4
+        with:
+          node-version: '18'
+          cache: 'yarn'
+          cache-dependency-path: backend/email/yarn.lock
  1. Consider combining jobs or using a matrix strategy to reduce duplication:
strategy:
  matrix:
    check: [eslint, prettier, typecheck]

These optimizations would make the CI faster and more reliable by ensuring consistent Node.js versions and leveraging GitHub's caching mechanism.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b6f1237 and dbeeead.

📒 Files selected for processing (8)
  • .github/workflows/ci-backend-email.yml (1 hunks)
  • backend/email/.prettierignore (1 hunks)
  • backend/email/emails/functions/send-test-email.ts (1 hunks)
  • backend/email/emails/new-endorsement.tsx (4 hunks)
  • backend/email/emails/new-match.tsx (2 hunks)
  • backend/email/emails/new-message.tsx (2 hunks)
  • backend/email/eslint.config.mjs (1 hunks)
  • backend/email/package.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
backend/email/emails/new-message.tsx (2)
common/src/envs/constants.ts (1)
  • DOMAIN (26-26)
common/src/love/og-image.ts (1)
  • getLoveOgImageUrl (17-28)
backend/email/emails/new-match.tsx (3)
common/src/love/lover.ts (1)
  • LoverRow (5-5)
common/src/love/og-image.ts (1)
  • getLoveOgImageUrl (17-28)
common/src/envs/constants.ts (1)
  • DOMAIN (26-26)
backend/email/emails/new-endorsement.tsx (1)
common/src/envs/constants.ts (1)
  • DOMAIN (26-26)
🔇 Additional comments (6)
backend/email/emails/functions/send-test-email.ts (1)

14-14: Good formatting improvement.

Adding the newline at end of file follows Unix conventions and standard formatting practices.

backend/email/.prettierignore (1)

1-1: Correct Prettier ignore configuration.

Excluding the lib/ directory from formatting is appropriate since it typically contains generated TypeScript compilation output that shouldn't be manually formatted.

backend/email/emails/new-endorsement.tsx (1)

67-69: Update property access if keeping current pattern.

If maintaining the current object-based approach, the property access is consistent with the pattern established earlier in the function.

backend/email/eslint.config.mjs (1)

12-12: Confirm the necessity of disabling @typescript-eslint/no-unused-expressions

Our automated checks didn’t uncover any pure expression statements in backend/email that would be flagged by this rule. Please ensure this override is intentional—e.g. for specific patterns like standalone assertions in tests—or remove it (or narrow its scope to the files/patterns that actually require it).

• backend/email/eslint.config.mjs (line 12): { '@typescript-eslint/no-unused-expressions': 'off' }

.github/workflows/ci-backend-email.yml (2)

1-14: LGTM! Well-structured workflow configuration.

The workflow is properly configured with:

  • Appropriate triggers for PR and push events
  • Path filtering to run only when backend/email files change
  • Exclusion of irrelevant file types (txt, md, png)
  • Correct default working directory setting

47-50: LGTM! Proper TypeScript checking strategy.

The two-step TypeScript checking approach is excellent:

  1. tsc -b ensures the project builds correctly
  2. tsc --noEmit --strict performs strict type checking without generating files

This catches both build issues and type safety violations effectively.

Comment thread backend/email/emails/new-message.tsx Outdated
Comment on lines +10 to +18
"@eslint/js": "9.32.0",
"@react-email/components": "0.0.33",
"eslint": "9.32.0",
"globals": "16.3.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-email": "3.0.7",
"resend": "4.1.2"
"resend": "4.1.2",
"typescript-eslint": "8.39.0"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Move ESLint dependencies to devDependencies.

ESLint and related tooling packages should be in devDependencies since they're only needed during development and CI, not at runtime.

   "dependencies": {
-    "@eslint/js": "9.32.0",
     "@react-email/components": "0.0.33",
-    "eslint": "9.32.0",
-    "globals": "16.3.0",
     "react": "19.0.0",
     "react-dom": "19.0.0",
     "react-email": "3.0.7",
     "resend": "4.1.2",
-    "typescript-eslint": "8.39.0"
   },
   "devDependencies": {
+    "@eslint/js": "9.32.0",
+    "eslint": "9.32.0",
+    "globals": "16.3.0",
     "@types/html-to-text": "9.0.4",
     "@types/prismjs": "1.26.5",
     "@types/react": "19.0.10",
-    "@types/react-dom": "19.0.4"
+    "@types/react-dom": "19.0.4",
+    "typescript-eslint": "8.39.0"
   }
📝 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
"@eslint/js": "9.32.0",
"@react-email/components": "0.0.33",
"eslint": "9.32.0",
"globals": "16.3.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-email": "3.0.7",
"resend": "4.1.2"
"resend": "4.1.2",
"typescript-eslint": "8.39.0"
"dependencies": {
"@react-email/components": "0.0.33",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-email": "3.0.7",
"resend": "4.1.2"
},
"devDependencies": {
"@eslint/js": "9.32.0",
"eslint": "9.32.0",
"globals": "16.3.0",
"@types/html-to-text": "9.0.4",
"@types/prismjs": "1.26.5",
"@types/react": "19.0.10",
"@types/react-dom": "19.0.4",
"typescript-eslint": "8.39.0"
}
🤖 Prompt for AI Agents
In backend/email/package.json around lines 10 to 18, ESLint and related packages
are incorrectly listed under dependencies. Move "@eslint/js", "eslint", and
"typescript-eslint" from dependencies to devDependencies to ensure they are only
installed during development and CI, not in production runtime.

Copy link
Copy Markdown

@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: 3

🔭 Outside diff range comments (2)
backend/email/emails/new-match.tsx (1)

87-92: Remove stale unsubscribeUrl from PreviewProps for consistency

PreviewProps includes a property not in the props type and not used. Remove it to avoid confusion and keep parity with other emails.

 NewMatchEmail.PreviewProps = {
   onUser: sinclairUser,
   matchedWithUser: jamesUser,
   matchedLover: jamesLover,
-  unsubscribeUrl: 'https://manifold.love/unsubscribe',
 } as NewMatchEmailProps
backend/email/emails/new-endorsement.tsx (1)

94-100: Remove unsubscribeUrl from PreviewProps to match the interface and avoid confusion

This property is deprecated in the component and not used.

 NewEndorsementEmail.PreviewProps = {
   fromUser: jamesUser,
   onUser: sinclairUser,
   endorsementText:
     "Sinclair is someone you want to have around because she injects creativity and humor into every conversation, and her laugh is infectious! Not to mention that she's a great employee, treats everyone with respect, and is even-tempered.",
-  unsubscribeUrl: 'https://manifold.love/unsubscribe',
 } as NewEndorsementEmailProps
♻️ Duplicate comments (1)
backend/email/emails/new-message.tsx (1)

94-100: Good: unused unsubscribeUrl removed from interface/preview

The previously raised lint issue is addressed here by removing unsubscribeUrl from both the interface and PreviewProps.

🧹 Nitpick comments (13)
backend/email/emails/new-match.tsx (4)

26-31: Prefer parameter destructuring and type inference to reduce verbosity and noise

You can destructure props in the signature and rely on inference to avoid redundant local declarations and explicit type annotations.

-export const NewMatchEmail = (newMatchEmailProps: NewMatchEmailProps) => {
-  const name: string = newMatchEmailProps.onUser.name.split(' ')[0]
-  const matchedWithUser: User = newMatchEmailProps.matchedWithUser
-  const matchedLover: LoverRow = newMatchEmailProps.matchedLover
-  const userImgSrc: string = getLoveOgImageUrl(matchedWithUser, matchedLover)
-  const userUrl: string = `https://${DOMAIN}/${matchedWithUser.username}`
+export const NewMatchEmail = ({
+  onUser,
+  matchedWithUser,
+  matchedLover,
+}: NewMatchEmailProps) => {
+  const name = onUser.name.split(' ')[0]
+  const userImgSrc = getLoveOgImageUrl(matchedWithUser, matchedLover)
+  const userUrl = `https://${DOMAIN}/${matchedWithUser.username}`

57-63: Add descriptive alt text for accessibility

The OG/profile image is content-bearing; use a descriptive alt instead of an empty string.

-                <Img
+                <Img
                   src={userImgSrc}
                   width="375"
                   height="200"
-                  alt=""
+                  alt={`${matchedWithUser.name}'s profile`}
                   style={profileImage}
                 />

133-145: Use numeric fontWeight instead of non-standard 'semibold'

'semibold' isn’t a standard CSS value and may be ignored by some email clients. Use 600.

 const button = {
   backgroundColor: '#ec489a',
   borderRadius: '12px',
   color: '#ffffff',
   fontFamily: 'Helvetica, Arial, sans-serif',
   fontSize: '16px',
-  fontWeight: 'semibold',
+  fontWeight: 600,
   textDecoration: 'none',
   textAlign: 'center' as const,
   display: 'inline-block',
   padding: '6px 10px',
   margin: '10px 0',
 }

72-80: Clean up commented unsubscribe markup or gate behind a feature flag

Leaving long commented JSX tends to linger. Either remove it or gate it behind a boolean and a prop when the feature is implemented. If you plan to bring it back later, add a TODO with a tracking issue.

I can wire a minimal “Manage notifications” link using DOMAIN and a static path if desired (e.g., https://${DOMAIN}/notifications).

backend/email/emails/new-endorsement.tsx (4)

26-34: Destructure props and simplify locals

Reduce boilerplate and improve readability by destructuring in the signature and using inferred types.

-export const NewEndorsementEmail = (
-  newEndorsementEmailProps: NewEndorsementEmailProps
-) => {
-  const onUser: User = newEndorsementEmailProps.onUser
-  const fromUser: User = newEndorsementEmailProps.fromUser
-  const name: string = onUser.name.split(' ')[0]
-
-  const endorsementUrl: string = `https://${DOMAIN}/${newEndorsementEmailProps.onUser.username}`
+export const NewEndorsementEmail = ({
+  onUser,
+  fromUser,
+  endorsementText,
+}: NewEndorsementEmailProps) => {
+  const name = onUser.name.split(' ')[0]
+  const endorsementUrl = `https://${DOMAIN}/${onUser.username}`
-                  <Text style={endorsementTextStyle}>
-                    "{newEndorsementEmailProps.endorsementText}"
-                  </Text>
+                  <Text style={endorsementTextStyle}>
+                    "{endorsementText}"
+                  </Text>

Also applies to: 67-69


58-64: Improve avatar alt text for accessibility

Provide a meaningful alt for screen readers.

-                  <Img
+                  <Img
                     src={fromUser.avatarUrl}
                     width="50"
                     height="50"
-                    alt=""
+                    alt={`${fromUser.name}'s avatar`}
                     style={avatarImage}
                   />

150-162: Use numeric fontWeight for better email client compatibility

Replace non-standard 'semibold' with 600.

 const button = {
   backgroundColor: '#ec489a',
   borderRadius: '12px',
   color: '#ffffff',
   fontFamily: 'Helvetica, Arial, sans-serif',
   fontSize: '16px',
-  fontWeight: 'semibold',
+  fontWeight: 600,
   textDecoration: 'none',
   textAlign: 'center' as const,
   display: 'inline-block',
   padding: '6px 10px',
   margin: '10px 0',
 }

79-86: Tidy up commented unsubscribe markup

Consider removing or adding a TODO with a tracking reference to avoid lingering commented JSX.

Happy to refactor this into a conditional block guarded by a feature flag or prop when you’re ready to implement unsubscribe.

backend/email/emails/new-message.tsx (4)

18-19: Remove commented-out import

Dead/commented imports tend to rot. Since it’s not used in PreviewProps either, remove it.

   jamesUser,
-  //sinclairLover,
   sinclairUser,

32-40: Destructure props and rely on inference for cleaner code

This mirrors the pattern applied across the other components.

-export const NewMessageEmail = (newMessageEmailProps: NewMessageEmailProps) => {
-  const name: string = newMessageEmailProps.toUser.name.split(' ')[0]
-  const creatorName: string = newMessageEmailProps.fromUser.name
-  const channelId: number = newMessageEmailProps.channelId
-  const messagesUrl: string = `https://${DOMAIN}/messages/${channelId}`
-  const userImgSrc: string = getLoveOgImageUrl(
-    newMessageEmailProps.fromUser,
-    newMessageEmailProps.fromUserLover
-  )
+export const NewMessageEmail = ({
+  toUser,
+  fromUser,
+  fromUserLover,
+  channelId,
+}: NewMessageEmailProps) => {
+  const name = toUser.name.split(' ')[0]
+  const creatorName = fromUser.name
+  const messagesUrl = `https://${DOMAIN}/messages/${channelId}`
+  const userImgSrc = getLoveOgImageUrl(fromUser, fromUserLover)

141-153: Use numeric fontWeight instead of 'semibold'

Email clients are stricter; use 600.

 const button = {
   backgroundColor: '#ec489a',
   borderRadius: '12px',
   color: '#ffffff',
   fontFamily: 'Helvetica, Arial, sans-serif',
   fontSize: '16px',
-  fontWeight: 'semibold',
+  fontWeight: 600,
   textDecoration: 'none',
   textAlign: 'center' as const,
   display: 'inline-block',
   padding: '6px 10px',
   margin: '10px 0',
 }

79-86: Consider removing the commented unsubscribe JSX

If you plan to reintroduce it later, add a TODO with a link to a tracking issue; otherwise remove to keep the template lean.

backend/email/emails/functions/helpers.tsx (1)

12-35: Optional: extract common sendEmail boilerplate

These three helpers share substantial structure. Consider a small internal helper that takes subject and react content to reduce duplication.

I can draft a generic sendNotificationEmail(privateUser, subject, react) that encapsulates the common null checks and sendEmail call if you want to proceed.

Also applies to: 37-68, 70-93

📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dbeeead and 5c74d91.

📒 Files selected for processing (4)
  • backend/email/emails/functions/helpers.tsx (6 hunks)
  • backend/email/emails/new-endorsement.tsx (4 hunks)
  • backend/email/emails/new-match.tsx (2 hunks)
  • backend/email/emails/new-message.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
backend/email/emails/functions/helpers.tsx (1)
common/src/user-notification-preferences.ts (1)
  • getNotificationDestinationsForUser (60-76)
backend/email/emails/new-message.tsx (2)
common/src/envs/constants.ts (1)
  • DOMAIN (26-26)
common/src/love/og-image.ts (1)
  • getLoveOgImageUrl (17-28)
backend/email/emails/new-endorsement.tsx (1)
common/src/envs/constants.ts (1)
  • DOMAIN (26-26)
backend/email/emails/new-match.tsx (3)
common/src/love/lover.ts (1)
  • LoverRow (5-5)
common/src/love/og-image.ts (1)
  • getLoveOgImageUrl (17-28)
common/src/envs/constants.ts (1)
  • DOMAIN (26-26)
🔇 Additional comments (1)
backend/email/emails/functions/helpers.tsx (1)

10-10: Verify sender domain alignment with linked/asset domains

From is set to no-reply@poly.love, while assets and links in templates point to manifold.love/DOMAIN. Ensure your sending domain alignment, SPF/DKIM/DMARC, and branding allow this mix to prevent deliverability issues.

Would you like me to scan the repo for other references to manifold.love vs. poly.love to assess consistency?

Comment on lines +16 to 18
const { sendToEmail /*, unsubscribeUrl*/ } =
getNotificationDestinationsForUser(privateUser, 'new_match')
if (!privateUser.email || !sendToEmail) return
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove commented unsubscribeUrl artifacts

Commented destructuring and props increase noise and can confuse future refactors. Remove them until the feature is implemented.

-  const { sendToEmail /*, unsubscribeUrl*/ } =
-    getNotificationDestinationsForUser(privateUser, 'new_match')
+  const { sendToEmail } =
+    getNotificationDestinationsForUser(privateUser, 'new_match')
@@
       <NewMatchEmail
         onUser={lover.user}
         matchedWithUser={matchedWithUser}
         matchedLover={lover}
-        /*unsubscribeUrl={unsubscribeUrl}*/
       />

Also applies to: 31-32

🤖 Prompt for AI Agents
In backend/email/emails/functions/helpers.tsx around lines 16-18 (and similarly
at lines 31-32), remove the commented-out unsubscribeUrl from the destructuring
and any commented props or variables related to unsubscribeUrl so the code only
destructures active fields (e.g., const { sendToEmail } =
getNotificationDestinationsForUser(...)), and delete the corresponding commented
usages to eliminate noise; if the unsubscribe feature is needed later,
reintroduce it as live code with tests.

Comment on lines +43 to 45
const { sendToEmail /*, unsubscribeUrl*/ } =
getNotificationDestinationsForUser(privateUser, 'new_message')
if (!privateUser.email || !sendToEmail) return
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove commented unsubscribeUrl in sendNewMessageEmail

Same rationale as above.

-  const { sendToEmail /*, unsubscribeUrl*/ } =
-    getNotificationDestinationsForUser(privateUser, 'new_message')
+  const { sendToEmail } =
+    getNotificationDestinationsForUser(privateUser, 'new_message')
@@
         toUser={toUser}
         channelId={channelId}
-        /*unsubscribeUrl={unsubscribeUrl}*/
       />

Also applies to: 64-65

🤖 Prompt for AI Agents
In backend/email/emails/functions/helpers.tsx around lines 43-45 and 64-65,
remove the commented out unsubscribeUrl in the destructuring of
getNotificationDestinationsForUser (i.e., change "const { sendToEmail /*,
unsubscribeUrl*/ } = ..." to only include sendToEmail) so that there are no
leftover commented properties; update both occurrences accordingly and ensure
formatting/commas remain valid after removal.

Comment on lines +76 to 78
const { sendToEmail /*, unsubscribeUrl*/ } =
getNotificationDestinationsForUser(privateUser, 'new_endorsement')
if (!privateUser.email || !sendToEmail) return
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove commented unsubscribeUrl in sendNewEndorsementEmail

Same cleanup.

-  const { sendToEmail /*, unsubscribeUrl*/ } =
-    getNotificationDestinationsForUser(privateUser, 'new_endorsement')
+  const { sendToEmail } =
+    getNotificationDestinationsForUser(privateUser, 'new_endorsement')
@@
         onUser={onUser}
         endorsementText={text}
-        /*unsubscribeUrl={unsubscribeUrl}*/
       />

Also applies to: 89-90

🤖 Prompt for AI Agents
In backend/email/emails/functions/helpers.tsx around lines 76-78 (and also
remove the same commented reference at lines 89-90), remove the commented out
"unsubscribeUrl" from the destructuring of getNotificationDestinationsForUser so
the code only destructures active properties (e.g., const { sendToEmail } =
...), and delete the redundant commented fragment entirely to keep the codebase
clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant