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

Skip to content

Conversation

@steven-tey
Copy link
Collaborator

@steven-tey steven-tey commented Jul 12, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced partner landing pages and earnings calculator previews by including detailed rewards and discount information.
  • Bug Fixes

    • Improved accuracy in displaying rewards and discounts within block components on partner pages.
  • Refactor

    • Streamlined data handling for rewards and discounts, ensuring consistent data context across relevant components.
    • Updated component prop types to support enriched program data.

@vercel
Copy link
Contributor

vercel bot commented Jul 12, 2025

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

Name Status Preview Updated (UTC)
dub ✅ Ready (Inspect) Visit Preview Jul 12, 2025 6:37am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 12, 2025

Walkthrough

This change refactors how rewards and discounts are fetched, processed, and passed into partner program landing page components. It introduces new hooks and helper functions to consistently merge rewards, discounts, and lander-specific data into the program prop for various UI blocks and updates the calculation logic for earnings accordingly.

Changes

File(s) Change Summary
apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/page.tsx Extends program prop passed to block components with rewards and discount fields.
apps/web/lib/actions/partners/generate-lander.ts Replaces custom API call with direct Prisma query; uses helper to extract rewards/discount; updates prompt formatting.
apps/web/ui/partners/design/modals/earnings-calculator-block-modal.tsx Adds useRewards/useDiscounts hooks; merges their data and landerData into the program prop for the earnings calculator.
apps/web/ui/partners/design/previews/lander-preview.tsx Uses useRewards/useDiscounts hooks; extends program prop with rewards, discounts, and landerData for block components.
apps/web/ui/partners/lander/blocks/earnings-calculator-block.tsx Uses helper to derive rewards; updates prop type; changes logic to use first reward; returns null if no rewards found.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI Component (Block)
    participant Hooks as useRewards/useDiscounts
    participant Helper as getProgramApplicationRewardsAndDiscount
    participant DB as Prisma

    UI->>Hooks: Fetch rewards and discounts
    UI->>Helper: Merge rewards, discounts, landerData into program prop
    UI->>Block: Render with extended program prop
Loading

Possibly related PRs

Poem

In the warren of code, rewards now abound,
Discounts and data are neatly passed ’round.
With helpers and hooks, the logic is clear—
Earnings and offers appear without fear.
The carrots of value are easy to see,
Thanks to these updates, from Dub and from me! 🥕

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

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 (1)
apps/web/ui/partners/lander/blocks/earnings-calculator-block.tsx (1)

32-32: Consider a fallback state instead of returning null.

Returning null when no rewards are found causes the entire earnings calculator block to disappear. Consider showing a placeholder or disabled state to maintain layout consistency and provide better user feedback.

- if (!rewards.length) return null;
+ if (!rewards.length) {
+   return (
+     <div className="space-y-5">
+       {showTitleAndDescription && (
+         <div className="space-y-2">
+           <BlockTitle title="Earnings calculator" />
+           <BlockDescription description="Earnings calculator will be available once rewards are configured." />
+         </div>
+       )}
+     </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 2d9b86e and 84ce1a4.

📒 Files selected for processing (5)
  • apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/page.tsx (1 hunks)
  • apps/web/lib/actions/partners/generate-lander.ts (3 hunks)
  • apps/web/ui/partners/design/modals/earnings-calculator-block-modal.tsx (3 hunks)
  • apps/web/ui/partners/design/previews/lander-preview.tsx (3 hunks)
  • apps/web/ui/partners/lander/blocks/earnings-calculator-block.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (5)
apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/page.tsx (1)
Learnt from: TWilson023
PR: dubinc/dub#2614
File: apps/web/ui/partners/design/previews/lander-preview.tsx:181-181
Timestamp: 2025-07-09T20:52:56.571Z
Learning: In apps/web/ui/partners/design/previews/lander-preview.tsx, the ellipsis wave animation delay calculation `3 - i * -0.15` is intentionally designed to create negative delays that offset each dot's animation cycle. This pattern works correctly for the intended ellipsis effect and should not be changed to positive incremental delays.
apps/web/ui/partners/design/previews/lander-preview.tsx (2)
Learnt from: TWilson023
PR: dubinc/dub#2614
File: apps/web/ui/partners/design/previews/lander-preview.tsx:181-181
Timestamp: 2025-07-09T20:52:56.571Z
Learning: In apps/web/ui/partners/design/previews/lander-preview.tsx, the ellipsis wave animation delay calculation `3 - i * -0.15` is intentionally designed to create negative delays that offset each dot's animation cycle. This pattern works correctly for the intended ellipsis effect and should not be changed to positive incremental delays.
Learnt from: TWilson023
PR: dubinc/dub#2519
File: apps/web/ui/analytics/utils.ts:35-37
Timestamp: 2025-06-16T19:21:23.506Z
Learning: In the `useAnalyticsFilterOption` function in `apps/web/ui/analytics/utils.ts`, the pattern `options?.context ?? useContext(AnalyticsContext)` is intentionally designed as a complete replacement strategy, not a merge. When `options.context` is provided, it should contain all required fields (`baseApiPath`, `queryString`, `selectedTab`, `requiresUpgrade`) and completely replace the React context, not be merged with it. This is used for dependency injection or testing scenarios.
apps/web/ui/partners/design/modals/earnings-calculator-block-modal.tsx (2)
Learnt from: TWilson023
PR: dubinc/dub#2614
File: apps/web/ui/partners/design/previews/lander-preview.tsx:181-181
Timestamp: 2025-07-09T20:52:56.571Z
Learning: In apps/web/ui/partners/design/previews/lander-preview.tsx, the ellipsis wave animation delay calculation `3 - i * -0.15` is intentionally designed to create negative delays that offset each dot's animation cycle. This pattern works correctly for the intended ellipsis effect and should not be changed to positive incremental delays.
Learnt from: TWilson023
PR: dubinc/dub#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/lib/actions/partners/generate-lander.ts (3)
Learnt from: TWilson023
PR: dubinc/dub#2614
File: apps/web/ui/partners/design/previews/lander-preview.tsx:181-181
Timestamp: 2025-07-09T20:52:56.571Z
Learning: In apps/web/ui/partners/design/previews/lander-preview.tsx, the ellipsis wave animation delay calculation `3 - i * -0.15` is intentionally designed to create negative delays that offset each dot's animation cycle. This pattern works correctly for the intended ellipsis effect and should not be changed to positive incremental delays.
Learnt from: devkiran
PR: dubinc/dub#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.
Learnt from: devkiran
PR: dubinc/dub#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/ui/partners/lander/blocks/earnings-calculator-block.tsx (2)
Learnt from: TWilson023
PR: dubinc/dub#2614
File: apps/web/ui/partners/design/previews/lander-preview.tsx:181-181
Timestamp: 2025-07-09T20:52:56.571Z
Learning: In apps/web/ui/partners/design/previews/lander-preview.tsx, the ellipsis wave animation delay calculation `3 - i * -0.15` is intentionally designed to create negative delays that offset each dot's animation cycle. This pattern works correctly for the intended ellipsis effect and should not be changed to positive incremental delays.
Learnt from: devkiran
PR: dubinc/dub#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 (2)
apps/web/ui/partners/design/previews/lander-preview.tsx (2)
apps/web/lib/swr/use-rewards.ts (1)
  • useRewards (6-25)
apps/web/lib/swr/use-discounts.ts (1)
  • useDiscounts (6-24)
apps/web/ui/partners/lander/blocks/earnings-calculator-block.tsx (2)
apps/web/lib/types.ts (1)
  • ProgramWithLanderDataProps (412-414)
apps/web/lib/partners/get-program-application-rewards.ts (1)
  • getProgramApplicationRewardsAndDiscount (11-66)
⏰ 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 (5)
apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/page.tsx (1)

59-63: LGTM: Clean enrichment of program prop with processed rewards and discount data.

The spreading pattern correctly preserves existing program properties while adding the processed rewards and discount from the helper function.

apps/web/ui/partners/lander/blocks/earnings-calculator-block.tsx (1)

26-34: LGTM: Proper use of helper function with defensive programming.

The helper function usage is correct and the early return prevents errors when no rewards are available. The type change to ProgramWithLanderDataProps is also appropriate.

apps/web/lib/actions/partners/generate-lander.ts (3)

35-43: LGTM: Direct Prisma query with proper relations.

The replacement of getProgramOrThrow with a direct Prisma query is clean and includes the necessary rewards and discounts relations for the helper function.


45-46: LGTM: Consistent use of helper function.

The helper function usage aligns with the pattern established in other files and properly extracts the processed rewards and discount data.


101-104: LGTM: Improved prompt generation with processed data.

The prompt now uses the properly formatted rewards and discount data instead of raw program properties, which should result in better AI-generated content.

Comment on lines +187 to +192
const { rewards } = useRewards();
const { discounts } = useDiscounts();
const landerData = useWatch({
control: brandingFormControl,
name: "landerData",
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Handle loading states for rewards and discounts data.

The useRewards and useDiscounts hooks return loading states, but they're not being handled here. If the data is still loading when passed to EarningsCalculatorBlock, it could cause rendering issues or incorrect calculations.

Consider handling the loading states:

  const { rewards } = useRewards();
  const { discounts } = useDiscounts();
+ 
+ if (!rewards || !discounts) {
+   return <div>Loading...</div>; // or some appropriate loading state
+ }
🤖 Prompt for AI Agents
In apps/web/ui/partners/design/modals/earnings-calculator-block-modal.tsx around
lines 187 to 192, the loading states returned by useRewards and useDiscounts
hooks are not handled, which may cause rendering or calculation issues if data
is not ready. Update the code to check the loading states from both hooks before
rendering EarningsCalculatorBlock, and display a loading indicator or fallback
UI until the data is fully loaded. This ensures that rewards and discounts data
passed to EarningsCalculatorBlock are valid and complete.

Comment on lines +54 to +55
const { rewards } = useRewards();
const { discounts } = useDiscounts();
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Handle loading states for rewards and discounts data.

Similar to the modal component, the loading states from useRewards and useDiscounts are not being handled, which could lead to undefined data being passed to block components during initial load.

Consider handling loading states before rendering blocks:

  const { rewards } = useRewards();
  const { discounts } = useDiscounts();
+ 
+ if (!rewards || !discounts) {
+   // Return early or show loading state for the affected blocks
+   return <div>Loading preview...</div>;
+ }
📝 Committable suggestion

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

Suggested change
const { rewards } = useRewards();
const { discounts } = useDiscounts();
const { rewards } = useRewards();
const { discounts } = useDiscounts();
if (!rewards || !discounts) {
// Return early or show loading state for the affected blocks
return <div>Loading preview...</div>;
}
🤖 Prompt for AI Agents
In apps/web/ui/partners/design/previews/lander-preview.tsx around lines 54 to
55, the loading states from useRewards and useDiscounts hooks are not handled,
which may cause undefined data issues. Update the code to check if rewards or
discounts are still loading before rendering the block components, and render a
loading indicator or return null until the data is ready to ensure safe data
usage.

@steven-tey
Copy link
Collaborator Author

@CodeRabbit final review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 12, 2025

Tip

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

🧩 Analysis chain

I'll conduct a comprehensive final review of your PR. Let me examine the key files to understand the implementation details and identify any potential issues.


🏁 Script executed:

#!/bin/bash
# Read the key files to understand the implementation
echo "=== Reading earnings calculator block component ==="
cat apps/web/ui/partners/lander/blocks/earnings-calculator-block.tsx

echo -e "\n=== Reading the helper function ==="
fd -t f "getProgramApplicationRewardsAndDiscount" --exec cat {}

echo -e "\n=== Reading generate-lander action ==="
cat apps/web/lib/actions/partners/generate-lander.ts

echo -e "\n=== Reading lander preview component ==="
cat apps/web/ui/partners/design/previews/lander-preview.tsx

Length of output: 26086


🏁 Script executed:

#!/bin/bash
# Search for the helper function implementation
echo "=== Searching for getProgramApplicationRewardsAndDiscount function ==="
rg -A 20 "getProgramApplicationRewardsAndDiscount" --type ts

echo -e "\n=== Checking if there are any type definitions ==="
rg "ProgramWithLanderDataProps" --type ts -A 5 -B 5

echo -e "\n=== Looking for the actual helper file ==="
fd -t f "get-program-application-rewards" --exec cat {}

Length of output: 56013


@steven-tey Here's my comprehensive final review of this PR. The refactoring looks solid overall, but I've identified several areas that could benefit from improvements:

🔍 Key Issues & Recommendations

1. Error Handling & Edge Cases

Issue: The earnings calculator can fail silently if reward data is malformed:

const reward = rewards[0];
const rewardAmount = reward.amount ?? 0; // Could still be null in DB

Recommendation: Add more robust validation:

const reward = rewards[0];
if (!reward || typeof reward.amount !== 'number') {
  console.warn('Invalid reward data in earnings calculator');
  return null;
}

2. Type Safety Concerns

Issue: The helper function accepts Prisma.JsonValue which provides no type safety:

landerData: Prisma.JsonValue;

Recommendation: Consider using a more specific type or adding runtime validation:

landerData: Prisma.JsonValue | ProgramLanderData;

3. Performance & Data Consistency

Issue: Different components fetch rewards/discounts inconsistently:

  • LanderPreview uses useRewards() and useDiscounts() hooks
  • Other components rely on program's included data
  • Helper function is called multiple times with potentially the same data

Recommendation: Standardize data fetching approach and consider memoization for the helper function.

4. Calculation Logic Robustness

Issue: The earnings calculation could produce incorrect results:

Math.floor(
  reward.type === "flat"
    ? (value * rewardAmount) / 100
    : revenue * (rewardAmount / 100),
)

Concerns:

  • No validation that reward.type is a valid value
  • Division by 100 assumes amounts are in cents, but this isn't documented
  • Math.floor could hide precision issues

5. Complex Fallback Logic

Issue: The helper function has intricate fallback logic that may be hard to maintain:

const reward =
  rewards.find((r) => r.id === landerReward && r.event === event) ||
  defaultReward;

Recommendation: Add comments explaining the business logic and consider breaking into smaller, more testable functions.

What's Working Well

  1. Consistent API: The helper function provides a single source of truth for application rewards/discounts
  2. Type Safety: The move to ProgramWithLanderDataProps improves type safety
  3. Separation of Concerns: Logic is properly separated from UI components
  4. Backwards Compatibility: Graceful fallbacks to default rewards/discounts

🧪 Suggested Tests

Consider adding tests for these edge cases:

  • Empty rewards array
  • Malformed lander data
  • Missing reward amounts
  • Invalid reward types
  • Null/undefined discount scenarios

🔧 Minor Improvements

  1. Add JSDoc comments to the helper function explaining the business logic
  2. Consider adding validation for reward amounts in the earnings calculator
  3. Standardize data fetching across all components
  4. Add error boundaries around components that use the helper function

The refactoring achieves its goal of centralizing reward/discount logic, but addressing these points would make it more robust and maintainable. Would you like me to elaborate on any of these recommendations?

Simplifies the program prop passed to block components by removing the spread of rewards and discount. The program object is now passed as-is.
@steven-tey steven-tey merged commit 63f6b98 into main Jul 12, 2025
3 of 6 checks passed
@steven-tey steven-tey deleted the fix-lander-calculator branch July 12, 2025 06:27
@coderabbitai coderabbitai bot mentioned this pull request Aug 14, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 15, 2025
@coderabbitai coderabbitai bot mentioned this pull request Nov 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants