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

Skip to content

Conversation

@TWilson023
Copy link
Collaborator

@TWilson023 TWilson023 commented Jul 22, 2025

Screenshot 2025-07-22 at 3 13 13 PM

Summary by CodeRabbit

  • New Features

    • Introduced a notification preferences page for partner users with toggles for commission and application approval notifications.
    • Notification emails for sales and application approvals are now sent individually to partner users who opted in, rather than only to the main partner email.
    • Added API endpoints and actions to retrieve and update partner notification preferences.
    • Added a new model for partner invites and extended partner user profiles with notification preferences.
  • Improvements

    • Added a new "Settings" section in the sidebar navigation for easy access to notification preferences.
    • Notification emails now include a direct link to manage notification settings.
  • Bug Fixes

    • Initialized notification preferences for new partner users during onboarding.
    • Backfilled missing notification preferences for existing partner users.

@vercel
Copy link
Contributor

vercel bot commented Jul 22, 2025

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

Name Status Preview Updated (UTC)
dub ✅ Ready (Inspect) Visit Preview Jul 22, 2025 9:35pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 22, 2025

"""

Walkthrough

This change introduces partner user notification preferences to the application. It adds new Prisma models for storing notification settings per partner user and partner invites. Server-side actions and API routes are added to fetch and update these preferences. Notification email logic is updated to send emails individually to users who opted in. New UI components and navigation for managing partner notification settings are included.

Changes

File(s) Change Summary
packages/prisma/schema/partner.prisma Added PartnerNotificationPreferences and PartnerInvite models; linked to PartnerUser and Partner respectively.
apps/web/lib/zod/schemas/partner-profile.ts Added exported partnerNotificationTypes Zod enum ("commissionCreated", "applicationApproved").
apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts Added GET API route to fetch partner user notification preferences.
apps/web/lib/actions/partners/update-partner-notification-preference.ts Added server action to update a partner user's notification preference.
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx Added client component for managing and updating notification preferences with optimistic UI updates.
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page.tsx Added page component for notification settings, wrapping the client component in layout wrappers.
apps/web/ui/layout/sidebar/partners-sidebar-nav.tsx Added "Settings" navigation group and sidebar area for partner notification settings.
apps/web/ui/layout/page-content/index.tsx Made titleInfo.href optional in PageContent component prop types and logic.
apps/web/lib/actions/partners/onboard-partner.ts Ensured new partner users are created with an empty notification preference object.
apps/web/lib/actions/partners/bulk-approve-partners.ts Modified partner fetching to include notification-preferring users; included user emails for notifications.
apps/web/lib/partners/bulk-approve-partners.ts Changed to send approval emails to each user who opted in, not just the partner's main email; updated function signature accordingly.
apps/web/lib/partners/approve-partner-enrollment.ts Changed to batch-send approval emails to all opted-in users; fetches users by notification preference.
apps/web/lib/api/partners/notify-partner-sale.ts Sends sale notification emails to all users who opted in, not just the partner's main email.
apps/web/lib/api/partners/notify-partner-application.ts Refactored to batch-send application approval emails using resend.batch.send instead of rate-limited single sends.
apps/web/scripts/backfill-notification-preferences.ts Added script to backfill missing notification preferences for partner users.
packages/email/src/templates/new-sale-alert-partner.tsx
packages/email/src/templates/partner-application-approved.tsx
Added notificationSettingsUrl prop to Footer in both email templates.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI (Notifications Page)
    participant API (GET/POST)
    participant Server Action
    participant DB

    User->>UI (Notifications Page): Visit settings/notifications
    UI (Notifications Page)->>API (GET): Fetch notification preferences
    API (GET)->>DB: Query PartnerNotificationPreferences
    DB-->>API (GET): Return preferences
    API (GET)-->>UI (Notifications Page): Send preferences
    User->>UI (Notifications Page): Toggle notification switch
    UI (Notifications Page)->>Server Action: updatePartnerNotificationPreference({type, value})
    Server Action->>DB: Update PartnerNotificationPreferences
    DB-->>Server Action: Confirm update
    Server Action-->>UI (Notifications Page): { ok: true }
Loading
sequenceDiagram
    participant System
    participant DB
    participant EmailService

    System->>DB: Fetch partner users with notificationPreference (sale/applicationApproved)
    DB-->>System: Return users and emails
    loop For each opted-in user
        System->>EmailService: Send notification email (personalized)
    end
Loading

Estimated code review effort

4 (~90 minutes)

Suggested reviewers

  • devkiran

Poem

In the warren of code, a new feature appears,
Notification toggles bring joy and cheers!
Rabbits hop in—settings now neat,
Emails sent out, preferences discrete.
With every new sale, or approval delight,
Partners choose how they get their insight.
🐇✨ Settings made simple, all through the night!
"""

✨ 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.

Comment on lines 63 to 65
notificationPreference: {
create: {},
},
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A PartnerNotificationPreferences record will be created when the partner is created, but we'll have to backfill this for existing partners.

@TWilson023 TWilson023 marked this pull request as ready for review July 22, 2025 19:22
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: 3

🧹 Nitpick comments (1)
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (1)

17-30: Consider moving notification definitions to a shared constants file.

The hardcoded notifications array could benefit from being moved to a shared constants file for better maintainability and reusability across the codebase.

Create a new constants file and move this definition:

// apps/web/lib/constants/partner-notifications.ts
export const PARTNER_NOTIFICATIONS = [
  {
    type: "sale" as const,
    icon: InvoiceDollar,
    title: "New sale",
    description: "Alert when a new sale is made.",
  },
  {
    type: "applicationApproved" as const,
    icon: CircleCheck,
    title: "Application approval",
    description: "Alert when an application to a program is approved.",
  },
] as const;

Then import and use it in the component:

+ import { PARTNER_NOTIFICATIONS } from "@/lib/constants/partner-notifications";
- const notifications = [
-   // ... array content
- ];

export function PartnerSettingsNotificationsPageClient() {
  // ... rest of component
  return (
    <div className="mt-2 grid grid-cols-1 gap-3">
-     {notifications.map(({ type, icon: Icon, title, description }) => (
+     {PARTNER_NOTIFICATIONS.map(({ type, icon: Icon, title, description }) => (
        // ... rest of JSX
      ))}
    </div>
  );
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4d3811f and ec4fb62.

📒 Files selected for processing (15)
  • apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts (1 hunks)
  • apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (1 hunks)
  • apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page.tsx (1 hunks)
  • apps/web/lib/actions/partners/bulk-approve-partners.ts (1 hunks)
  • apps/web/lib/actions/partners/onboard-partner.ts (1 hunks)
  • apps/web/lib/actions/partners/update-partner-notification-preference.ts (1 hunks)
  • apps/web/lib/api/partners/notify-partner-sale.ts (2 hunks)
  • apps/web/lib/partners/approve-partner-enrollment.ts (4 hunks)
  • apps/web/lib/partners/bulk-approve-partners.ts (2 hunks)
  • apps/web/lib/zod/schemas/partner-profile.ts (1 hunks)
  • apps/web/ui/layout/page-content/index.tsx (1 hunks)
  • apps/web/ui/layout/sidebar/partners-sidebar-nav.tsx (4 hunks)
  • packages/email/src/templates/new-sale-alert-partner.tsx (1 hunks)
  • packages/email/src/templates/partner-application-approved.tsx (1 hunks)
  • packages/prisma/schema/partner.prisma (1 hunks)
🧠 Learnings (8)
packages/email/src/templates/partner-application-approved.tsx (1)

Learnt from: devkiran
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.

packages/email/src/templates/new-sale-alert-partner.tsx (1)

Learnt from: devkiran
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.

apps/web/lib/partners/approve-partner-enrollment.ts (1)

Learnt from: devkiran
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.

apps/web/lib/zod/schemas/partner-profile.ts (2)

Learnt from: devkiran
PR: #2433
File: apps/web/app/api/workspaces/[idOrSlug]/billing/payment-methods/route.ts:74-76
Timestamp: 2025-05-29T09:47:33.583Z
Learning: When Zod enum validation is used (e.g., z.enum(PAYMENT_METHOD_TYPES)), it ensures the validated value is one of the valid enum values, making subsequent type casts to the corresponding TypeScript types safe without additional validation.

Learnt from: devkiran
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.

apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (1)

Learnt from: devkiran
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.

apps/web/lib/actions/partners/bulk-approve-partners.ts (1)

Learnt from: devkiran
PR: #2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.

apps/web/lib/partners/bulk-approve-partners.ts (1)

Learnt from: TWilson023
PR: #2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in WorkspaceAuth which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.

apps/web/ui/layout/sidebar/partners-sidebar-nav.tsx (1)

Learnt from: devkiran
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.

🧬 Code Graph Analysis (5)
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page.tsx (3)
apps/web/ui/layout/page-content/index.tsx (1)
  • PageContent (11-97)
apps/web/ui/layout/page-width-wrapper.tsx (1)
  • PageWidthWrapper (4-21)
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (1)
  • PartnerSettingsNotificationsPageClient (32-116)
apps/web/lib/api/partners/notify-partner-sale.ts (1)
packages/email/src/templates/new-sale-alert-partner.tsx (1)
  • NewSaleAlertPartner (17-140)
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (3)
apps/web/lib/zod/schemas/partner-profile.ts (1)
  • partnerNotificationTypes (130-130)
apps/web/lib/actions/partners/update-partner-notification-preference.ts (1)
  • updatePartnerNotificationPreference (14-37)
packages/ui/src/icons/index.tsx (1)
  • Icon (77-77)
apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts (1)
apps/web/lib/auth/partner.ts (1)
  • withPartnerProfile (26-85)
apps/web/lib/actions/partners/update-partner-notification-preference.ts (2)
apps/web/lib/zod/schemas/partner-profile.ts (1)
  • partnerNotificationTypes (130-130)
apps/web/lib/actions/safe-action.ts (1)
  • authPartnerActionClient (84-112)
🧰 Additional context used
🧠 Learnings (8)
packages/email/src/templates/partner-application-approved.tsx (1)

Learnt from: devkiran
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.

packages/email/src/templates/new-sale-alert-partner.tsx (1)

Learnt from: devkiran
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.

apps/web/lib/partners/approve-partner-enrollment.ts (1)

Learnt from: devkiran
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.

apps/web/lib/zod/schemas/partner-profile.ts (2)

Learnt from: devkiran
PR: #2433
File: apps/web/app/api/workspaces/[idOrSlug]/billing/payment-methods/route.ts:74-76
Timestamp: 2025-05-29T09:47:33.583Z
Learning: When Zod enum validation is used (e.g., z.enum(PAYMENT_METHOD_TYPES)), it ensures the validated value is one of the valid enum values, making subsequent type casts to the corresponding TypeScript types safe without additional validation.

Learnt from: devkiran
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.

apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (1)

Learnt from: devkiran
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.

apps/web/lib/actions/partners/bulk-approve-partners.ts (1)

Learnt from: devkiran
PR: #2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.

apps/web/lib/partners/bulk-approve-partners.ts (1)

Learnt from: TWilson023
PR: #2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in WorkspaceAuth which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.

apps/web/ui/layout/sidebar/partners-sidebar-nav.tsx (1)

Learnt from: devkiran
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.

🧬 Code Graph Analysis (5)
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page.tsx (3)
apps/web/ui/layout/page-content/index.tsx (1)
  • PageContent (11-97)
apps/web/ui/layout/page-width-wrapper.tsx (1)
  • PageWidthWrapper (4-21)
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (1)
  • PartnerSettingsNotificationsPageClient (32-116)
apps/web/lib/api/partners/notify-partner-sale.ts (1)
packages/email/src/templates/new-sale-alert-partner.tsx (1)
  • NewSaleAlertPartner (17-140)
apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (3)
apps/web/lib/zod/schemas/partner-profile.ts (1)
  • partnerNotificationTypes (130-130)
apps/web/lib/actions/partners/update-partner-notification-preference.ts (1)
  • updatePartnerNotificationPreference (14-37)
packages/ui/src/icons/index.tsx (1)
  • Icon (77-77)
apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts (1)
apps/web/lib/auth/partner.ts (1)
  • withPartnerProfile (26-85)
apps/web/lib/actions/partners/update-partner-notification-preference.ts (2)
apps/web/lib/zod/schemas/partner-profile.ts (1)
  • partnerNotificationTypes (130-130)
apps/web/lib/actions/safe-action.ts (1)
  • authPartnerActionClient (84-112)
⏰ 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 (22)
apps/web/lib/zod/schemas/partner-profile.ts (1)

129-130: LGTM! Well-structured notification type schema.

The Zod enum definition for notification types is clean and follows established patterns in the codebase. The two notification types align perfectly with the partner notification features being implemented.

packages/email/src/templates/partner-application-approved.tsx (1)

172-175: LGTM! Consistent integration with notification settings.

The addition of the notificationSettingsUrl prop to the Footer component provides users with a direct link to manage their notification preferences, which enhances the user experience.

packages/email/src/templates/new-sale-alert-partner.tsx (1)

131-134: LGTM! Consistent with other email templates.

The notification settings URL addition matches the pattern established in the partner application approved template, ensuring a consistent user experience across all partner notification emails.

apps/web/lib/actions/partners/onboard-partner.ts (1)

63-65: LGTM! Proper initialization of notification preferences.

The nested creation of notification preferences ensures new partner users have their settings initialized during onboarding. The empty object will correctly use schema defaults.

Note: As mentioned in previous comments, existing partners will need backfilling of notification preferences, but that's outside the scope of this change.

apps/web/lib/actions/partners/bulk-approve-partners.ts (1)

36-49: LGTM! Well-structured query for notification preferences.

The nested Prisma query correctly filters partner users based on their notification preferences and includes the necessary user data for individualized email notifications. This approach ensures only users who opted in for application approval notifications receive emails.

apps/web/ui/layout/page-content/index.tsx (1)

21-21: LGTM! Good enhancement for component flexibility.

Making the href property optional in the titleInfo object type is a sensible change that allows for more flexible usage patterns while maintaining backward compatibility.

Also applies to: 29-29

apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page.tsx (1)

5-19: Well-structured notification settings page implementation.

The component follows good patterns with clear separation of concerns. The descriptive subtitle effectively communicates the personal nature of these notification preferences.

apps/web/lib/partners/approve-partner-enrollment.ts (3)

83-96: Good implementation of notification preference filtering.

The query correctly includes partner users who have opted in for application approval notifications.


140-142: Add null check for email filtering.

Good use of filter to ensure only valid emails are included.


166-192: Batch email implementation looks correct.

The transition from single email to batch emails for opted-in users is well implemented. The conditional check ensures no empty batch is sent when there are no opted-in users.

apps/web/lib/api/partners/notify-partner-sale.ts (3)

50-63: Proper implementation of user notification preferences.

The query correctly fetches partner users who have opted in for sale notifications.


112-114: Clean email extraction with null filtering.

Good defensive programming by filtering out null emails.


117-131: Well-implemented batch notification with rate limiting.

Good use of the limiter for rate-controlled email sending. The conditional logic ensures no processing occurs when there are no opted-in users.

apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (1)

92-111: LGTM: Well-implemented optimistic updates with proper error handling.

The Switch component implementation correctly:

  • Uses optimistic updates for immediate UI feedback
  • Properly handles loading states by disabling toggles
  • Includes null checks for preferences data
  • Maintains consistent state management
apps/web/lib/actions/partners/update-partner-notification-preference.ts (1)

8-11: LGTM: Proper schema validation.

The Zod schema correctly validates the input with:

  • Type restriction using partnerNotificationTypes enum
  • Boolean value validation
packages/prisma/schema/partner.prisma (2)

71-71: LGTM: Proper optional relationship definition.

The optional one-to-one relationship is correctly defined, allowing existing partner users to not have notification preferences initially.


77-85: LGTM: Well-designed notification preferences model.

The model design is excellent:

  • Proper unique constraint on partnerUserId ensures one-to-one relationship
  • Cascade delete maintains referential integrity
  • Sensible default values (opt-in by default) provide good user experience
  • Boolean fields align with the Zod enum types defined in the codebase
apps/web/lib/partners/bulk-approve-partners.ts (2)

33-35: LGTM: Proper type definition for notification-aware partner data.

The updated type correctly reflects that partner users are now filtered based on their notification preferences and includes the necessary email information.


90-116: LGTM: Correct implementation of per-user email notifications.

The email sending logic properly:

  • Handles multiple users per partner
  • Filters out null email addresses
  • Sends individual emails to each user who opted in
  • Maintains the same email content structure
  • Uses efficient batch sending
apps/web/ui/layout/sidebar/partners-sidebar-nav.tsx (3)

64-70: LGTM: Well-structured navigation group addition.

The new "Settings" navigation group follows the established pattern with:

  • Descriptive name and description
  • Appropriate icon (Gear)
  • Correct href pointing to the notifications page
  • Proper active state logic

199-216: LGTM: Consistent navigation area structure.

The new partnerSettings area maintains consistency with existing areas:

  • Proper title and direction
  • Logical "Account" section grouping
  • Appropriate icon for notifications
  • Correct href and exact matching

264-272: LGTM: Proper path matching logic with correct precedence.

The updated currentArea logic correctly:

  • Places /settings check before /profile to avoid conflicts
  • Maintains proper precedence order
  • Uses consistent pattern matching approach

@steven-tey
Copy link
Collaborator

@CodeRabbit final review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 22, 2025

Tip

For best results, initiate chat on the files or code changes.

@steven-tey This PR looks excellent and ready for merge! 🎉

Final Review Summary

Strong Implementation

  • Database Design: Well-structured Prisma schema with proper relationships, constraints, and cascading deletes
  • API Security: Properly authenticated endpoints using withPartnerProfile wrapper
  • UI/UX: Clean, intuitive notification settings page with optimistic updates and loading states
  • Email Logic: Smart update to send notifications only to opted-in users instead of blanket partner emails

Architecture Highlights 🏗️

  • Follows established patterns with server actions and API routes
  • Type-safe with Zod schemas and TypeScript throughout
  • Proper separation of concerns between client/server components
  • Backward compatibility maintained while adding new functionality

Comprehensive Coverage 📋

  • ✅ Database migrations and models
  • ✅ API endpoints for CRUD operations
  • ✅ Server actions with proper authentication
  • ✅ React components with proper state management
  • ✅ Navigation integration
  • ✅ Email template updates
  • ✅ Onboarding flow integration

Code Quality 💎

  • Clean, readable code with proper error handling
  • Consistent naming conventions
  • Good use of optimistic updates for better UX
  • Proper TypeScript types throughout

This is a well-executed feature that enhances the partner experience while maintaining code quality and security standards. Ready to ship! 🚀

ᕱ⑅ᕱ excited rabbit noises

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

🧹 Nitpick comments (1)
apps/web/lib/api/partners/notify-partner-application.ts (1)

61-63: Fix unnecessary ternary operator.

The static analysis tool correctly identified this as a useless ternary operator. Since you're converting a truthy/falsy value to a boolean, you can simplify this expression.

-        autoApprovePartners: program.autoApprovePartnersEnabledAt
-          ? true
-          : false,
+        autoApprovePartners: Boolean(program.autoApprovePartnersEnabledAt),

Or alternatively:

-        autoApprovePartners: program.autoApprovePartnersEnabledAt
-          ? true
-          : false,
+        autoApprovePartners: !!program.autoApprovePartnersEnabledAt,
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c3e3903 and cdef3c4.

📒 Files selected for processing (4)
  • apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts (1 hunks)
  • apps/web/lib/api/partners/notify-partner-application.ts (2 hunks)
  • apps/web/lib/api/partners/notify-partner-sale.ts (3 hunks)
  • apps/web/lib/partners/bulk-approve-partners.ts (4 hunks)
🧬 Code Graph Analysis (1)
apps/web/lib/api/partners/notify-partner-application.ts (1)
packages/email/src/templates/partner-application-received.tsx (1)
  • PartnerApplicationReceived (17-178)
🪛 Biome (1.9.4)
apps/web/lib/api/partners/notify-partner-application.ts

[error] 61-63: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/lib/api/partners/notify-partner-sale.ts
  • apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts
  • apps/web/lib/partners/bulk-approve-partners.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/web/lib/api/partners/notify-partner-application.ts (1)
packages/email/src/templates/partner-application-received.tsx (1)
  • PartnerApplicationReceived (17-178)
🪛 Biome (1.9.4)
apps/web/lib/api/partners/notify-partner-application.ts

[error] 61-63: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

⏰ 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)
apps/web/lib/api/partners/notify-partner-application.ts (2)

1-2: LGTM: Imports support the batch email functionality.

The new imports for VARIANT_TO_FROM_MAP and chunk utility are appropriate for the batch email sending refactor and improve consistency in email handling.

Also applies to: 6-6


71-76: LGTM: Well-implemented batch email sending.

The batch sending approach with 100 emails per chunk is efficient and appropriate for email service limits. Using Promise.all for concurrent batch processing will significantly improve performance compared to individual email sending.

The optional chaining on resend?.batch.send() properly handles potential undefined cases.

@steven-tey
Copy link
Collaborator

@CodeRabbit final review please

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 22, 2025

Tip

For best results, initiate chat on the files or code changes.

@steven-tey This PR represents a well-executed and comprehensive implementation of partner notification settings! Here's my final review:

🎯 Implementation Excellence

Database Design

  • Clean Prisma schema with proper relationships and constraints
  • PartnerNotificationPreferences model with sensible defaults (both preferences default to true)
  • Proper cascade deletes and foreign key relationships
  • PartnerInvite model addition for future extensibility

Security & Authentication 🔒

  • All API routes properly wrapped with withPartnerProfile authentication
  • Server actions use authPartnerActionClient for secure operations
  • Proper user/partner context validation throughout

UI/UX Excellence 🎨

  • Intuitive notification settings page with clear descriptions
  • Optimistic updates for immediate feedback
  • Loading states and error handling
  • Clean integration with existing navigation structure

Email Logic Improvement 📧

  • Smart refactor from partner-level to user-level notifications
  • Batch email sending with proper rate limiting
  • Users only receive notifications they've opted into
  • Email templates updated with unsubscribe links

🏗️ Architecture Strengths

  • Type Safety: Full TypeScript coverage with Zod schemas
  • Consistency: Follows established patterns throughout the codebase
  • Separation of Concerns: Clean client/server component separation
  • Backward Compatibility: Existing functionality preserved while adding new features

🔍 Code Quality Assessment

  • Clean, readable code with proper error handling
  • Consistent naming conventions and file organization
  • Proper use of React hooks and optimistic updates
  • Good integration with existing components and utilities

Ready for Merge

This is a production-ready feature that enhances the partner experience while maintaining high code quality standards. The implementation is thorough, secure, and follows best practices.

Recommendation: APPROVE - Ready to ship! 🚀

Great work on this comprehensive feature addition! 🌟

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

🧹 Nitpick comments (2)
apps/web/scripts/backfill-notification-preferences.ts (1)

12-12: Consider the batch size for larger datasets.

The current batch size of 100 is reasonable, but for very large partner user bases, you might want to make this configurable or add progress logging to track multiple runs.

apps/web/lib/api/partners/notify-partner-sale.ts (1)

113-116: Add null check for partner users array.

While the filter should handle null emails, consider adding a length check to avoid unnecessary processing when no partner users have opted in.

 const partnerEmailsToNotify = partner.users
   .map(({ user }) => user.email)
   .filter(Boolean) as string[];

+if (partnerEmailsToNotify.length === 0 && workspaceUsers.length === 0) {
+  console.log("No recipients found for partner sale notification");
+  return;
+}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between cdef3c4 and 97381c3.

📒 Files selected for processing (5)
  • apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts (1 hunks)
  • apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx (1 hunks)
  • apps/web/lib/api/partners/notify-partner-sale.ts (3 hunks)
  • apps/web/scripts/backfill-notification-preferences.ts (1 hunks)
  • packages/prisma/schema/partner.prisma (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/app/(ee)/api/partner-profile/notification-preferences/route.ts
  • apps/web/app/(ee)/partners.dub.co/(dashboard)/settings/notifications/page-client.tsx
  • packages/prisma/schema/partner.prisma
⏰ 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)
apps/web/lib/api/partners/notify-partner-sale.ts (2)

51-65: Excellent refactor to use notification preferences.

The query now properly filters partner users based on their commission notification preferences, which aligns perfectly with the new notification system.


118-143: Well-structured email batching implementation.

The email construction logic is clean and properly separates partner and workspace user notifications. The use of chunking for batch sending is a good performance optimization.

@steven-tey steven-tey merged commit 8e9d00f into main Jul 22, 2025
8 checks passed
@steven-tey steven-tey deleted the partner-notifications branch July 22, 2025 21:42
@coderabbitai coderabbitai bot mentioned this pull request Aug 15, 2025
This was referenced Oct 13, 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