Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@marcusljf
Copy link
Collaborator

@marcusljf marcusljf commented Nov 19, 2025

Introduces a new React email template for thanking programs after making a payout to partners. The template displays the program name, payout amount, number of partners, and includes a link to view invoices.

CleanShot 2025-11-18 at 20 40 53@2x Screenshot 2025-11-18 at 8 46 48 PM

Summary by CodeRabbit

  • New Features

    • Payouts now send automated thank-you emails using a new template, showing program name, partner count, and formatted payout amount.
    • Batch email delivery added to notify multiple recipients efficiently.
  • User Communication

    • Email subjects now include the formatted payout amount for clearer notifications.
    • Confirmation emails include invoice links and improved responsive layout for better readability.

Introduces a new React email template for thanking programs after making a payout to partners. The template displays the program name, payout amount, number of partners, and includes a link to view invoices.
@vercel
Copy link
Contributor

vercel bot commented Nov 19, 2025

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

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Nov 19, 2025 5:57pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 19, 2025

Walkthrough

Adds batched email dispatch and a new ProgramPayoutThankYou email template to the payouts workflow; modifies payout processing to include workspace slug and payout fields, fetch user emails via Prisma, and queue batch emails after booking payouts; updates payout email subjects to include formatted amounts.

Changes

Cohort / File(s) Summary
Payout processing & email dispatch
apps/web/app/(ee)/api/cron/payouts/process/process-payouts.ts
Uses queueBatchEmail to queue ProgramPayoutThankYou after processing payouts; adjusts Prisma updates to include workspace users/emails; expands ProcessPayoutsProps.workspace pick to include slug and payout-related fields.
Email templates map
apps/web/lib/email/email-templates-map.ts
Registers the new ProgramPayoutThankYou template in EMAIL_TEMPLATES_MAP.
New email template
packages/email/src/templates/program-payout-thank-you.tsx
Adds ProgramPayoutThankYou React email template (props: email, workspace.slug, program.name, payout.amount, payout.partnersCount); formats amount, pluralizes "partner", links to invoices.
Payout notification subject updates
apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts, apps/web/app/(ee)/api/stripe/connect/webhook/payout-paid.ts
Replace static email subjects with dynamic subjects including formatted payout amount and currency via currencyFormatter.

Sequence Diagram(s)

sequenceDiagram
    actor Cron
    participant Processor as process-payouts.ts
    participant DB as Prisma
    participant EmailQueue as queueBatchEmail

    Cron->>Processor: trigger payout processing
    Processor->>DB: update/process payouts (include users.emails)
    DB-->>Processor: payouts + users
    Processor->>DB: book payout / update payoutsUsage (include users)
    DB-->>Processor: updated workspace + users
    rect rgb(200,230,201)
        note right of Processor: New — batch email dispatch
        Processor->>EmailQueue: queueBatchEmail(ProgramPayoutThankYou, recipients[], payload)
        EmailQueue-->>Processor: queued ack
    end
    Processor-->>Cron: finished
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring attention:
    • Prisma include blocks returning user emails and handling empty/nullable lists.
    • Correctness of expanded ProcessPayoutsProps.workspace shape across callers.
    • Email payload shape passed to queueBatchEmail matches template props (amount units, slug, partnersCount).
    • Subject formatting consistency where currencyFormatter is used.

Possibly related PRs

  • #3058 — Modifies payouts processing/email flow and uses queueBatchEmail and payout templates.
  • #3011 — Touches the same payout processing file and the email templates map.
  • #3125 — Changes batch email queuing and payloads for payout notifications.

Suggested reviewers

  • devkiran

Poem

🐰 I hopped through code with tiny paws,

Queued bright notes to spread the cause,
Numbers neat and amounts in view,
Partners cheered — invoices too,
A grateful thump, a carrot for you 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective of the PR: introducing a new React email template for program payout thank you notifications.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch thankyou-email

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 934f9f6 and d5000d2.

📒 Files selected for processing (1)
  • packages/email/src/templates/program-payout-thank-you.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/email/src/templates/program-payout-thank-you.tsx

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

Comment @coderabbitai help to get the list of available commands and usage tips.

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 30f55f5 and 546d484.

📒 Files selected for processing (1)
  • packages/email/src/templates/program-payout-thankyou.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: devkiran
Repo: dubinc/dub PR: 2448
File: packages/email/src/templates/partner-program-summary.tsx:0-0
Timestamp: 2025-05-29T04:45:18.504Z
Learning: In the PartnerProgramSummary email template (packages/email/src/templates/partner-program-summary.tsx), the stat titles are hardcoded constants ("Clicks", "Leads", "Sales", "Earnings") that will always match the ICONS object keys after toLowerCase() conversion, so icon lookup failures are not possible.
📚 Learning: 2025-05-29T04:45:18.504Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2448
File: packages/email/src/templates/partner-program-summary.tsx:0-0
Timestamp: 2025-05-29T04:45:18.504Z
Learning: In the PartnerProgramSummary email template (packages/email/src/templates/partner-program-summary.tsx), the stat titles are hardcoded constants ("Clicks", "Leads", "Sales", "Earnings") that will always match the ICONS object keys after toLowerCase() conversion, so icon lookup failures are not possible.

Applied to files:

  • packages/email/src/templates/program-payout-thankyou.tsx
🧬 Code graph analysis (1)
packages/email/src/templates/program-payout-thankyou.tsx (3)
packages/utils/src/functions/currency-formatter.ts (1)
  • currencyFormatter (7-22)
packages/email/src/react-email.d.ts (11)
  • Html (4-4)
  • Head (5-5)
  • Preview (18-18)
  • Tailwind (19-19)
  • Body (6-6)
  • Container (7-7)
  • Section (8-8)
  • Img (13-13)
  • Heading (16-16)
  • Text (15-15)
  • Link (14-14)
packages/email/src/templates/program-payout-reminder.tsx (1)
  • ProgramPayoutReminder (19-106)
🪛 Biome (2.1.2)
packages/email/src/templates/program-payout-thankyou.tsx

[error] 118-119: Unexpected token. Did you mean {'}'} or }?

(parse)


[error] 119-119: expected < but instead the file ends

the file ends here

(parse)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
packages/email/src/templates/program-payout-thankyou.tsx (2)

17-45: Overall template structure and responsive styling look solid

Props typing, sensible defaults, preview line, heading hierarchy, Tailwind classes, and the small-screen media query for the amount/heading all align well with the existing email templates in this repo. No additional issues from my side here.

Also applies to: 50-101, 111-113


102-108: URL is correct and consistent across the codebase

The invoices URL in the email is properly formatted and matches the app's routing. The invoices page defines partnerPayout as a valid invoice type, and the API endpoint validates this type in its enum. The same link pattern is used consistently in other parts of the app (e.g., payout-stats.tsx and success pages), confirming this is the intended destination for the partner payout invoices view.

Comment on lines 47 to 49
return (
<Html>
<Html>
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 | 🔴 Critical

Remove duplicate <Html> wrapper causing JSX parse error

There are two opening <Html> tags but only one closing </Html>, which is exactly what Biome is flagging and will prevent this file from compiling.

Apply this minimal fix:

-  return (
-    <Html>
-    <Html>
+  return (
+    <Html>

Also applies to: 117-118

🤖 Prompt for AI Agents
In packages/email/src/templates/program-payout-thankyou.tsx around lines 47-49
(and also at lines 117-118), there are duplicated opening <Html> tags with only
one closing </Html>, causing a JSX parse error; remove the extra opening <Html>
tag(s) so each <Html> has a matching closing tag (i.e., leave a single <Html>
wrapper at the top and remove the duplicate(s) at the noted lines) and re-run
the build to confirm the file compiles.

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)
apps/web/app/(ee)/api/cron/payouts/process/process-payouts.ts (1)

282-299: Consider adding an idempotency key for email batching.

The email batching implementation looks correct and properly constructs the template props. However, unlike the Stripe payment intent (line 238), no idempotency key is provided to queueBatchEmail. If the function is retried after the payment intent succeeds but before/during email sending, duplicate thank you emails could be sent to workspace users.

Consider adding an idempotency key based on the invoice ID:

  await queueBatchEmail<typeof ProgramPayoutThankYou>(
    users.map(({ user }) => ({
      to: user.email!,
      subject: `Thank you for your ${currencyFormatter(totalPayoutAmount)} payout to ${res.count} partners`,
      templateName: "ProgramPayoutThankYou",
      templateProps: {
        email: user.email!,
        workspace,
        program: {
          name: program.name,
        },
        payout: {
          amount: totalPayoutAmount,
          partnersCount: res.count,
        },
      },
    })),
+   {
+     idempotencyKey: `payout-thank-you/${invoice.id}`,
+   },
  );
packages/email/src/templates/program-payout-thank-you.tsx (1)

26-26: Consider a more realistic default preview amount.

The default amount of 450000000 cents equals $4,500,000, which is quite high for preview purposes. Consider using a more typical amount like 450000 cents ($4,500) or 4500000 cents ($45,000) for easier preview testing.

  payout = {
-   amount: 450000000,
+   amount: 4500000,  // $45,000
    partnersCount: 12,
  },
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 546d484 and 956b8eb.

📒 Files selected for processing (3)
  • apps/web/app/(ee)/api/cron/payouts/process/process-payouts.ts (5 hunks)
  • apps/web/lib/email/email-templates-map.ts (1 hunks)
  • packages/email/src/templates/program-payout-thank-you.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-05-29T04:45:18.504Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2448
File: packages/email/src/templates/partner-program-summary.tsx:0-0
Timestamp: 2025-05-29T04:45:18.504Z
Learning: In the PartnerProgramSummary email template (packages/email/src/templates/partner-program-summary.tsx), the stat titles are hardcoded constants ("Clicks", "Leads", "Sales", "Earnings") that will always match the ICONS object keys after toLowerCase() conversion, so icon lookup failures are not possible.

Applied to files:

  • apps/web/lib/email/email-templates-map.ts
  • packages/email/src/templates/program-payout-thank-you.tsx
📚 Learning: 2025-11-17T05:19:11.961Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3113
File: apps/web/app/(ee)/api/cron/payouts/charge-succeeded/send-paypal-payouts.ts:65-75
Timestamp: 2025-11-17T05:19:11.961Z
Learning: In the Dub codebase, `sendBatchEmail` (implemented in packages/email/src/send-via-resend.ts) handles filtering of emails with invalid `to` addresses internally. Call sites can safely use non-null assertions on email addresses because the email sending layer will filter out any entries with null/undefined `to` values before sending. This centralized validation pattern is intentional and removes the need for filtering at individual call sites.

Applied to files:

  • apps/web/app/(ee)/api/cron/payouts/process/process-payouts.ts
🧬 Code graph analysis (2)
apps/web/app/(ee)/api/cron/payouts/process/process-payouts.ts (4)
packages/prisma/index.ts (1)
  • prisma (3-9)
apps/web/lib/email/queue-batch-email.ts (1)
  • queueBatchEmail (18-87)
packages/email/src/templates/program-payout-thank-you.tsx (1)
  • ProgramPayoutThankYou (17-118)
packages/utils/src/functions/currency-formatter.ts (1)
  • currencyFormatter (7-22)
packages/email/src/templates/program-payout-thank-you.tsx (2)
packages/utils/src/functions/currency-formatter.ts (1)
  • currencyFormatter (7-22)
packages/email/src/templates/program-payout-reminder.tsx (1)
  • ProgramPayoutReminder (19-106)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (7)
apps/web/lib/email/email-templates-map.ts (1)

6-6: LGTM!

The new email template is properly imported and registered in the templates map, following the same pattern as existing templates.

Also applies to: 14-14

apps/web/app/(ee)/api/cron/payouts/process/process-payouts.ts (3)

4-4: LGTM!

The imports for queueBatchEmail and ProgramPayoutThankYou are correct and necessary for the new email notification feature.

Also applies to: 12-12


26-26: LGTM!

Adding slug to the workspace type is necessary for constructing the invoice link in the email template.


242-262: Verify email recipients: all workspace users vs. payout initiator only.

The update now fetches all workspace users and their emails. This means the thank you email will be sent to all users in the workspace, not just the user who initiated the payout (userId parameter). Confirm this is the intended behavior.

If you want to send the email only to the initiating user, you'll need to filter or fetch that specific user instead:

include: {
  users: {
    where: {
      userId: userId,
    },
    select: {
      user: {
        select: {
          email: true,
        },
      },
    },
  },
},
packages/email/src/templates/program-payout-thank-you.tsx (3)

1-15: LGTM!

All necessary imports are present for the email template, including utility functions (currencyFormatter, pluralize), React Email components, and the Footer component.


42-45: LGTM!

The amount formatting correctly removes decimal places for a cleaner display in the thank you message. The formatter defaults to USD, which aligns with the payout processing logic where amounts are always stored in USD cents.


47-117: LGTM!

The email template structure is well-designed:

  • Responsive styles handle mobile layouts appropriately
  • The clamp-based font sizing provides smooth responsiveness for the amount display
  • Pluralization is correctly applied to "partner"/"partners"
  • The invoice link properly uses workspace.slug and includes the type=partnerPayout query parameter
  • Footer component is correctly integrated

The hardcoded app.dub.co domain is consistent with other email templates in the codebase (e.g., program-payout-reminder.tsx).

@steven-tey steven-tey merged commit 9e3e503 into main Nov 19, 2025
7 of 8 checks passed
@steven-tey steven-tey deleted the thankyou-email branch November 19, 2025 18:04
@coderabbitai coderabbitai bot mentioned this pull request Dec 17, 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.

3 participants