-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Custom reward tooltip descriptions #3144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@steven-tey has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 5 minutes and 39 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
WalkthroughAdds a new tooltipDescription field end-to-end: schema, DB field, server actions, form bindings, UI rendering, a getRewardPayload helper, and a reward preview card; tooltipDescription is validated, persisted, and prioritized for tooltip content when present. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Form as Add/Edit Reward Form
participant Helper as getRewardPayload
participant Action as Create/Update Action
participant DB as Prisma DB
participant UI as Display Components
User->>Form: Fill reward + tooltipDescription
Form->>Helper: Submit FormData
Helper->>Helper: Normalize modifiers, convert currency→cents, compute amounts
Helper-->>Form: Payload (includes tooltipDescription)
Form->>Action: Call create/update with payload
Action->>DB: Persist reward (tooltipDescription stored)
DB-->>Action: Confirm
Action-->>UI: Return reward object
alt tooltipDescription present
UI->>UI: Render tooltip using tooltipDescription
else modifiers present
UI->>UI: Render modifiers tooltip
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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. Comment |
There was a problem hiding this 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 (3)
apps/web/ui/partners/rewards/reward-preview-card.tsx (1)
134-181: Align avatar “+X” label with actual previewed partners
PartnerPreviewOrCountalways maps over allpreviewPartners, but the “+X” label is based onpartnersCount > 3and assumes only 3 are shown in the avatar row. IfpreviewPartnersever contains more than 3 items, the UI could show more avatars than implied by+{partnersCount - 3}.If upstream doesn’t already cap
previewPartnersto 3, consider either slicing locally:const visiblePartners = previewPartners.slice(0, 3); const extraCount = Math.max(0, partnersCount - visiblePartners.length);or documenting the expectation that
previewPartners.length <= 3.apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx (2)
18-23: SharedgetRewardPayloadhelper is solid; consider reusingsafeParsein preview if perf becomes a concernThe new
getRewardPayloadcentralizes:
- Currency normalization for both main amount and per‑modifier conditions.
Infinity→nullconversion formaxDuration(global and per‑modifier).- Type/shape validation of modifiers via
rewardConditionsArraySchema.parse.Using this helper in
onSubmitkeeps create/update payload construction consistent and keeps the error handling for invalid conditions (setError("root.logic", ...)+ toast) in one place.Given it’s also used in the live preview, you’re now running a full zod
parseon every form change. That’s probably fine at current scale, but if the form grows or you see perf issues, you could switch the preview path tosafeParseand only show the preview when it succeeds, avoiding try/catch exceptions in the hot render path.Structurally, the helper and its use in
onSubmitlook correct.Also applies to: 87-142, 300-317
182-183: Clarify lifecycle betweendescriptionandtooltipDescriptionwhen removing the custom descriptionThe tooltip wiring is clean:
tooltipDescriptionis in form defaults andwatch.- UI uses
InlineBadgePopoverRichTextAreawithREWARD_TOOLTIP_DESCRIPTION_MAX_LENGTH.- Backend will receive
tooltipDescriptionviagetRewardPayload’s spread ofdata.One behavioral nuance: the “Remove reward” button in this block only sets
descriptiontonull:onClick={() => setValue("description", null, { shouldDirty: true }) }
tooltipDescriptionis left untouched, so you can end up with:
- No custom description (sheet section closed because
description === null).- A still‑persisted
tooltipDescriptionthat surfaces inProgramRewardModifiersTooltip, but has no visible editing UI until the pencil button is toggled again.If the intent is “disable the whole custom description + tooltip block,” consider also clearing
tooltipDescriptionhere:onClick={() => { setValue("description", null, { shouldDirty: true }); setValue("tooltipDescription", "", { shouldDirty: true }); }}(or whatever “empty” value your schema expects).
If you do want to support “tooltip only” rewards, it might be worth making that explicit in the copy and keeping an explicit control to clear just the tooltip.
Also applies to: 221-231, 485-525, 531-533
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
apps/web/lib/actions/partners/create-reward.ts(2 hunks)apps/web/lib/actions/partners/update-reward.ts(2 hunks)apps/web/lib/zod/schemas/rewards.ts(2 hunks)apps/web/ui/partners/program-reward-description.tsx(2 hunks)apps/web/ui/partners/program-reward-list.tsx(1 hunks)apps/web/ui/partners/program-reward-modifiers-tooltip.tsx(1 hunks)apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx(10 hunks)apps/web/ui/partners/rewards/reward-preview-card.tsx(1 hunks)apps/web/ui/shared/inline-badge-popover.tsx(4 hunks)packages/prisma/schema/reward.prisma(1 hunks)packages/ui/src/tooltip.tsx(2 hunks)
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: TWilson023
Repo: dubinc/dub PR: 2673
File: apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx:56-66
Timestamp: 2025-07-30T15:25:13.936Z
Learning: In apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx, the form schema uses partial condition objects to allow users to add empty/unconfigured condition fields without type errors, while submission validation uses strict schemas to ensure data integrity. This two-stage validation pattern improves UX by allowing progressive completion of complex forms.
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/profile-details-form.tsx:180-189
Timestamp: 2025-09-24T15:50:16.414Z
Learning: TWilson023 prefers to keep security vulnerability fixes separate from refactoring PRs when the vulnerable code is existing and was only moved/relocated rather than newly introduced.
📚 Learning: 2025-07-30T15:29:54.131Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2673
File: apps/web/ui/partners/rewards/rewards-logic.tsx:268-275
Timestamp: 2025-07-30T15:29:54.131Z
Learning: In apps/web/ui/partners/rewards/rewards-logic.tsx, when setting the entity field in a reward condition, dependent fields (attribute, operator, value) should be reset rather than preserved because different entities (customer vs sale) have different available attributes. Maintaining existing fields when the entity changes would create invalid state combinations and confusing UX.
Applied to files:
apps/web/lib/actions/partners/update-reward.tsapps/web/lib/actions/partners/create-reward.tsapps/web/ui/partners/program-reward-list.tsxapps/web/ui/partners/program-reward-description.tsxapps/web/ui/partners/rewards/reward-preview-card.tsxapps/web/ui/partners/rewards/add-edit-reward-sheet.tsx
📚 Learning: 2025-08-14T05:17:51.825Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2735
File: apps/web/lib/actions/partners/delete-reward.ts:33-41
Timestamp: 2025-08-14T05:17:51.825Z
Learning: In the partner groups system, a rewardId can only belong to one group, establishing a one-to-one relationship between rewards and groups. This means using Prisma's `update` method (rather than `updateMany`) is appropriate when updating groups by rewardId.
Applied to files:
apps/web/lib/actions/partners/update-reward.ts
📚 Learning: 2025-08-26T14:20:23.943Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2736
File: apps/web/app/api/workspaces/[idOrSlug]/notification-preferences/route.ts:13-14
Timestamp: 2025-08-26T14:20:23.943Z
Learning: The updateNotificationPreference action in apps/web/lib/actions/update-notification-preference.ts already handles all notification preference types dynamically, including newBountySubmitted, through its schema validation using the notificationTypes enum and Prisma's dynamic field update pattern.
Applied to files:
apps/web/lib/actions/partners/update-reward.ts
📚 Learning: 2025-07-30T15:25:13.936Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2673
File: apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx:56-66
Timestamp: 2025-07-30T15:25:13.936Z
Learning: In apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx, the form schema uses partial condition objects to allow users to add empty/unconfigured condition fields without type errors, while submission validation uses strict schemas to ensure data integrity. This two-stage validation pattern improves UX by allowing progressive completion of complex forms.
Applied to files:
apps/web/lib/actions/partners/update-reward.tsapps/web/lib/actions/partners/create-reward.tsapps/web/ui/partners/program-reward-list.tsxapps/web/lib/zod/schemas/rewards.tsapps/web/ui/partners/program-reward-description.tsxapps/web/ui/partners/rewards/reward-preview-card.tsxapps/web/ui/partners/rewards/add-edit-reward-sheet.tsx
📚 Learning: 2025-09-12T17:31:10.548Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2833
File: apps/web/lib/actions/partners/approve-bounty-submission.ts:53-61
Timestamp: 2025-09-12T17:31:10.548Z
Learning: In approve-bounty-submission.ts, the logic `bounty.rewardAmount ?? rewardAmount` is intentional. Bounties with preset reward amounts should use those fixed amounts, and the rewardAmount override parameter is only used when bounty.rewardAmount is null/undefined (for custom reward bounties). This follows the design pattern where bounties are either "flat rate" (fixed amount) or "custom" (variable amount set during approval).
Applied to files:
apps/web/lib/actions/partners/create-reward.tsapps/web/ui/partners/program-reward-description.tsxapps/web/ui/partners/rewards/add-edit-reward-sheet.tsx
📚 Learning: 2025-09-24T16:09:52.724Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/ui/partners/online-presence-form.tsx:181-186
Timestamp: 2025-09-24T16:09:52.724Z
Learning: The cn utility function in this codebase uses tailwind-merge, which automatically resolves conflicting Tailwind classes by giving precedence to later classes in the className string. Therefore, patterns like `cn("gap-6", variant === "settings" && "gap-4")` are valid and will correctly apply gap-4 when the condition is true.
Applied to files:
packages/ui/src/tooltip.tsx
📚 Learning: 2025-10-15T01:05:43.266Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2958
File: apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx:432-457
Timestamp: 2025-10-15T01:05:43.266Z
Learning: In apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx, defer refactoring the custom MenuItem component (lines 432-457) to use the shared dub/ui MenuItem component to a future PR, as requested by steven-tey.
Applied to files:
apps/web/ui/shared/inline-badge-popover.tsx
📚 Learning: 2025-09-24T16:10:37.349Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/ui/partners/partner-about.tsx:11-11
Timestamp: 2025-09-24T16:10:37.349Z
Learning: In the Dub codebase, the team prefers to import Icon as a runtime value from "dub/ui" and uses Icon as both a type and variable name in component props, even when this creates shadowing. This is their established pattern and should not be suggested for refactoring.
Applied to files:
apps/web/ui/shared/inline-badge-popover.tsx
📚 Learning: 2025-09-24T15:47:40.293Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/about-you-form.tsx:152-157
Timestamp: 2025-09-24T15:47:40.293Z
Learning: The Button component from dub/ui automatically adds type="button" when an onClick prop is passed, preventing accidental form submissions without requiring explicit type specification.
Applied to files:
apps/web/ui/shared/inline-badge-popover.tsx
📚 Learning: 2025-09-24T15:47:40.293Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/about-you-form.tsx:152-157
Timestamp: 2025-09-24T15:47:40.293Z
Learning: The Button component from dub/ui automatically adds type="button" when an onClick prop is passed, preventing accidental form submissions without requiring explicit type specification. The implementation uses: type={onClick ? "button" : type}
Applied to files:
apps/web/ui/shared/inline-badge-popover.tsx
🧬 Code graph analysis (7)
apps/web/ui/partners/program-reward-list.tsx (1)
apps/web/ui/partners/program-reward-modifiers-tooltip.tsx (1)
ProgramRewardModifiersTooltip(32-49)
apps/web/ui/partners/program-reward-modifiers-tooltip.tsx (1)
packages/ui/src/tooltip.tsx (1)
InfoTooltip(159-165)
packages/ui/src/tooltip.tsx (1)
packages/ui/src/rich-text-area/rich-text-provider.tsx (1)
PROSE_STYLES(20-24)
apps/web/ui/partners/program-reward-description.tsx (2)
apps/web/lib/types.ts (2)
RewardProps(536-536)DiscountProps(463-463)apps/web/ui/partners/program-reward-modifiers-tooltip.tsx (1)
ProgramRewardModifiersTooltip(32-49)
apps/web/ui/shared/inline-badge-popover.tsx (3)
packages/ui/src/rich-text-area/rich-text-provider.tsx (1)
RichTextProvider(69-242)packages/ui/src/rich-text-area/index.tsx (1)
RichTextArea(9-32)packages/ui/src/rich-text-area/rich-text-toolbar.tsx (1)
RichTextToolbar(16-129)
apps/web/ui/partners/rewards/reward-preview-card.tsx (6)
apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx (2)
useAddEditRewardForm(85-85)getRewardPayload(87-142)apps/web/ui/partners/constants.ts (1)
REWARD_EVENTS(3-25)apps/web/ui/partners/program-reward-description.tsx (1)
ProgramRewardDescription(7-110)apps/web/lib/types.ts (1)
EnrolledPartnerProps(451-451)packages/ui/src/table/table.tsx (2)
useTable(51-243)Table(341-675)packages/utils/src/constants/misc.ts (1)
OG_AVATAR_URL(29-29)
apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx (4)
apps/web/lib/types.ts (1)
RewardConditionsArray(559-559)apps/web/lib/zod/schemas/rewards.ts (4)
rewardConditionsArraySchema(156-158)ENTITY_ATTRIBUTE_TYPES(39-64)REWARD_DESCRIPTION_MAX_LENGTH(178-178)REWARD_TOOLTIP_DESCRIPTION_MAX_LENGTH(179-179)apps/web/ui/shared/inline-badge-popover.tsx (2)
InlineBadgePopover(38-90)InlineBadgePopoverRichTextArea(316-381)apps/web/ui/partners/rewards/reward-preview-card.tsx (1)
RewardPreviewCard(14-46)
⏰ 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 (11)
packages/ui/src/tooltip.tsx (1)
11-11: LGTM: Condensed prose styling for tooltipsThe addition of condensed prose styling reduces vertical spacing in tooltip content, which is appropriate for compact tooltip displays.
Also applies to: 33-33
apps/web/ui/shared/inline-badge-popover.tsx (2)
38-90: LGTM: Extended InlineBadgePopover with optional styling variantsThe addition of
showOptionalandcontentClassNameprops provides flexible styling options while maintaining backward compatibility. The neutral color variant for optional fields is a good UX pattern.
316-381: LGTM: Well-structured rich text area componentThe
InlineBadgePopoverRichTextAreacomponent properly integrates rich text editing with:
- Markdown support with bold, italic, and links
- Keyboard shortcut (Cmd/Ctrl+Enter) to close popover
- Character count display
- Markdown mode indicator
The implementation follows the established
RichTextProviderpattern used elsewhere in the codebase.apps/web/lib/actions/partners/update-reward.ts (1)
26-26: LGTM: tooltipDescription added to update flowThe
tooltipDescriptionfield follows the same pattern as the existingdescriptionfield with appropriate null fallback. The schema validation ensures proper constraints are applied.Also applies to: 59-59
packages/prisma/schema/reward.prisma (1)
16-16: LGTM: Optional tooltipDescription field addedThe optional
tooltipDescriptionfield is appropriate for storing additional descriptive content. The nullable String type is consistent with the existingdescriptionfield pattern.apps/web/lib/actions/partners/create-reward.ts (1)
30-30: LGTM: tooltipDescription added to creation flowThe
tooltipDescriptionfield is properly integrated into the reward creation flow, following the same pattern as the existingdescriptionfield with appropriate null fallback.Also applies to: 68-68
apps/web/ui/partners/program-reward-modifiers-tooltip.tsx (1)
35-48: LGTM: Tooltip content logic supports custom descriptionsThe component correctly handles both
tooltipDescriptionand modifiers content:
- Returns early when neither exists
- Prioritizes
tooltipDescriptionwhen present- Applies left-aligned styling for custom descriptions (more natural for reading longer text)
- Falls back to structured modifiers content
apps/web/ui/partners/program-reward-list.tsx (1)
70-77: LGTM: Tooltip rendering condition broadened for custom descriptionsThe rendering condition now correctly shows the tooltip when either modifiers exist or
tooltipDescriptionis present. TheBoolean()coercion ensures type safety and is consistent with the tooltip component's rendering logic.apps/web/lib/zod/schemas/rewards.ts (1)
170-170: LGTM: Well-structured schema additions with proper constraintsThe changes introduce
tooltipDescriptionwith clear length constraints:
- Extracted magic number into
REWARD_DESCRIPTION_MAX_LENGTHconstant (good refactoring)- Added
REWARD_TOOLTIP_DESCRIPTION_MAX_LENGTH(250 chars) for longer tooltip content- Both fields are properly validated and nullish
- Exported constants enable UI components to display character limits
The longer max length for
tooltipDescription(250) vsdescription(100) appropriately accommodates more detailed explanatory content.Also applies to: 178-193
apps/web/ui/partners/program-reward-description.tsx (1)
14-24: Prop narrowing and tooltip condition look consistent with tooltipDescription usageNarrowing
rewardto aPick<RewardProps, ...>that includestooltipDescriptionmatches how this component is used (particularly from the preview payload) and keeps the dependency surface small while still satisfyingconstructRewardAmountand the tooltip logic.The updated modifiers block:
{showModifiersTooltip && (!!reward.modifiers?.length || Boolean(reward.tooltipDescription)) && ( <> {" "} <ProgramRewardModifiersTooltip reward={reward} /> </> )}is aligned with
ProgramRewardModifiersTooltip’s own guard (!reward?.modifiers?.length && !reward?.tooltipDescription) and ensures the info icon appears even when only a custom tooltip (no modifiers) is configured.No issues from a correctness or type‑safety perspective here.
Also applies to: 32-79
apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx (1)
487-507: Nice integration of description limits and live previewHooking
InlineBadgePopoverInputandInlineBadgePopoverRichTextAreaup toREWARD_DESCRIPTION_MAX_LENGTHandREWARD_TOOLTIP_DESCRIPTION_MAX_LENGTHkeeps the UI aligned with zod constraints and surfaces limits directly to the user.Placing
<RewardPreviewCard />inline with the sheet and discount partners card makes the new tooltip behavior easy to verify in real time while editing.No functional issues spotted in this section.
Also applies to: 509-525, 548-555
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.