-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Partner messages panel updates #2913
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
On smaller screens, the Help and Support links were below screen heights, so it was a complete rework of this section was done to tighten everything up and to make everything a bit more consistent and readable.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughReplaces the in-page rewards list with a new ProgramRewardsPanel component, updates UI layouts and classes in the messages page, adjusts help link styling, and publicly exports ProgramRewardModifiersTooltipContent. Introduces ProgramRewardsPanel to render rewards and optional discounts with tooltip support. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Page as Messages Page
participant Panel as ProgramRewardsPanel
participant Tooltip as Reward Modifiers Tooltip
User->>Page: Open program messages dashboard
Page->>Panel: Render rewards (+optional discount)
Panel->>Panel: Build items (amount + duration text)
alt Reward has modifiers
Panel-->>Tooltip: Attach tooltip content
end
User-->>Tooltip: Hover/Focus reward with modifiers
Tooltip-->>User: Show modifiers details
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests
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: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/web/app/(ee)/partners.dub.co/(dashboard)/messages/[programSlug]/page-client.tsx(6 hunks)apps/web/ui/partners/program-help-links.tsx(1 hunks)apps/web/ui/partners/program-reward-modifiers-tooltip.tsx(1 hunks)apps/web/ui/partners/program-rewards-panel.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/web/ui/partners/program-rewards-panel.tsx (3)
apps/web/lib/types.ts (2)
RewardProps(509-509)DiscountProps(445-445)apps/web/ui/partners/program-reward-modifiers-tooltip.tsx (1)
ProgramRewardModifiersTooltipContent(48-99)apps/web/lib/api/sales/construct-reward-amount.ts (1)
constructRewardAmount(5-61)
apps/web/app/(ee)/partners.dub.co/(dashboard)/messages/[programSlug]/page-client.tsx (2)
packages/utils/src/functions/urls.ts (1)
getPrettyUrl(130-138)apps/web/ui/partners/program-rewards-panel.tsx (1)
ProgramRewardsPanel(29-109)
⏰ 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 (10)
apps/web/ui/partners/program-help-links.tsx (1)
54-54: LGTM! Hover animation refinement improves UX.The transition from static horizontal padding to dynamic hover-based padding creates a subtle "grow on hover" effect that's more space-efficient on smaller screens while maintaining visual feedback.
apps/web/ui/partners/program-reward-modifiers-tooltip.tsx (1)
48-48: LGTM! Proper component modularization.Exporting
ProgramRewardModifiersTooltipContentenables reuse in the newProgramRewardsPanelcomponent, promoting DRY principles.apps/web/app/(ee)/partners.dub.co/(dashboard)/messages/[programSlug]/page-client.tsx (6)
17-17: LGTM! Import updated for new component.The import correctly references the new
ProgramRewardsPanelcomponent.
322-336: LGTM! Avatar and layout optimizations for smaller screens.Reducing avatar size and switching to vertical stack improves space efficiency on mobile devices, consistent with PR objectives.
341-392: LGTM! Improved referral link UI with copy functionality.The redesigned input with gradient fade overlay and integrated copy button provides better UX. The gradient overlay correctly uses
pointer-events-noneto avoid interfering with input interaction, and the toast notification on copy enhances user feedback.
396-437: LGTM! Performance section renamed and spacing optimized.The rename from "Stats" to "Performance" is more descriptive, and the padding adjustments improve space efficiency while maintaining all data rendering logic and loading states.
451-458: LGTM! Consistent spacing applied to Help & support section.Padding adjustments align with the overall spacing optimization strategy across all panel sections.
439-448: Remove redundant null-safety suggestion. A fallback (programEnrollment.rewards ?? []) is already applied, soProgramRewardsPanelalways receives an array.Likely an incorrect or invalid review comment.
apps/web/ui/partners/program-rewards-panel.tsx (2)
16-27: LGTM! Compact tooltip implementation.The custom tooltip with reduced icon size (
h-3.5 w-3.5) maintains functionality while supporting the space optimization goals.
111-111: LGTM! Proper displayName for debugging.Setting
displayNameon the memoized component aids in React DevTools debugging.
| export const ProgramRewardsPanel = memo( | ||
| ({ rewards, discount }: ProgramRewardsPanelProps) => { | ||
| const sortedFilteredRewards = rewards.filter((r) => r.amount >= 0); | ||
|
|
||
| const rewardItems = [ | ||
| ...sortedFilteredRewards.map((reward) => ({ | ||
| icon: REWARD_EVENTS[reward.event].icon, | ||
| label: reward.description || ( | ||
| <> | ||
| {constructRewardAmount(reward)}{" "} | ||
| {reward.event === "sale" && reward.maxDuration === 0 ? ( | ||
| <>for the first sale</> | ||
| ) : ( | ||
| <>per {reward.event}</> | ||
| )} | ||
| {reward.maxDuration === null ? ( | ||
| <> | ||
| {" "} | ||
| for the{" "} | ||
| <strong className="font-semibold">customer's lifetime</strong> | ||
| </> | ||
| ) : reward.maxDuration && reward.maxDuration > 1 ? ( | ||
| <> | ||
| {" "} | ||
| for{" "} | ||
| <strong className="font-semibold"> | ||
| {reward.maxDuration % 12 === 0 | ||
| ? `${reward.maxDuration / 12} year${reward.maxDuration / 12 > 1 ? "s" : ""}` | ||
| : `${reward.maxDuration} months`} | ||
| </strong> | ||
| </> | ||
| ) : null} | ||
| {!!reward.modifiers?.length && ( | ||
| <> | ||
| {" "} | ||
| <CustomRewardModifiersTooltip reward={reward} /> | ||
| </> | ||
| )} | ||
| </> | ||
| ), | ||
| })), | ||
| ...(discount | ||
| ? [ | ||
| { | ||
| icon: Gift, | ||
| label: discount.description || ( | ||
| <> | ||
| New users get {constructRewardAmount(discount)} off{" "} | ||
| {discount.maxDuration === null | ||
| ? "for their lifetime" | ||
| : discount.maxDuration === 0 | ||
| ? "for their first purchase" | ||
| : discount.maxDuration === 1 | ||
| ? "for their first month" | ||
| : discount.maxDuration && discount.maxDuration > 1 | ||
| ? `for ${discount.maxDuration} months` | ||
| : null} | ||
| </> | ||
| ), | ||
| }, | ||
| ] | ||
| : []), | ||
| ]; | ||
|
|
||
| if (rewardItems.length === 0) return null; | ||
|
|
||
| return ( | ||
| <div className="grid grid-cols-1"> | ||
| {rewardItems.map(({ icon: Icon, label }, index) => ( | ||
| <div | ||
| key={index} | ||
| className="text-content-default flex items-start gap-2 rounded-md py-1.5 text-sm" | ||
| > | ||
| <Icon className="size-4 shrink-0 translate-y-px" /> | ||
| <div>{label}</div> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| ); | ||
| }, | ||
| ); |
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.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Review duration logic and key usage.
A few observations:
-
Index as key (line 99): Using
indexas the key can cause React rendering issues if the rewards array order changes. Consider using a stable identifier likereward.idor a combination of properties. -
Duration edge case (lines 44-60): The logic doesn't explicitly handle
maxDuration === 1for rewards (though it's handled for discounts at line 81-82). For consistency, consider:
- ) : reward.maxDuration && reward.maxDuration > 1 ? (
+ ) : reward.maxDuration === 1 ? (
+ <>
+ {" "}
+ for <strong className="font-semibold">1 month</strong>
+ </>
+ ) : reward.maxDuration && reward.maxDuration > 1 ? (- Amount filter (line 31): The filter
r.amount >= 0excludes negative rewards. Verify this is intentional behavior, as negative amounts might represent clawbacks or penalties.
🏁 Script executed:
#!/bin/bash
# Verify if negative reward amounts are valid in the schema and how they should be displayed
rg -nP --type=ts -C5 'amount.*number|RewardSchema' apps/web/lib/zod/schemas/rewards.tsLength of output: 1543
Replace index‐based key, add missing 1-month case, and reconsider amount filter.
-
Replace
key={index}with a stable identifier (e.g.key={reward.id}andkey={discount.id}) to avoid React reconciliation issues. -
(Optional) Add an explicit
maxDuration === 1branch for rewards so that “for 1 month” is rendered:- ) : reward.maxDuration && reward.maxDuration > 1 ? ( + ) : reward.maxDuration === 1 ? ( + <> + {" "} + for <strong className="font-semibold">1 month</strong> + </> + ) : reward.maxDuration && reward.maxDuration > 1 ? (
-
(Optional) Since the Zod
createOrUpdateRewardSchemaenforcesamount ≥ 0,rewards.filter(r => r.amount >= 0)will never drop valid items—consider removing this filter if negative values aren’t meaningful in the UI.
🤖 Prompt for AI Agents
In apps/web/ui/partners/program-rewards-panel.tsx around lines 29 to 109, the PR
review asks to stop using an index-based React key, add an explicit 1-month
wording branch, and reconsider the amount filter: replace key={index} with
stable keys (use reward.id for each mapped reward item and discount.id for the
discount item), add an explicit maxDuration === 1 case in the reward label
rendering so it displays “for 1 month” (mirror the discount logic), and remove
or justify the rewards.filter(r => r.amount >= 0) line since the schema already
enforces amount >= 0 (delete the filter if negatives are impossible, or add a
comment explaining why it’s kept).
On smaller screens, the Help and Support links were below laptop heights, so reworked this section to tighten everything up and to make everything more consistent and consumable.
A new rewards section was created to not impact other places that file is being used.
Summary by CodeRabbit
New Features
Style