Hid offer type selector for yearly retention offers#26606
Hid offer type selector for yearly retention offers#26606minimaluminium merged 1 commit intomainfrom
Conversation
WalkthroughThe change modifies the Details section rendering logic in the retention offer editor component. Previously, a bordered container with two ButtonSelect options (percent and free_months) was always rendered. Now, the container and percent-option ButtonSelect are conditionally rendered only when cadence is set to monthly. For yearly cadence, the percent option is not displayed. This alters the available offer-type options based on the selected cadence and changes the surrounding DOM structure in the monthly cadence view. 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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.
🧹 Nitpick comments (1)
apps/admin-x-settings/src/components/settings/growth/offers/edit-retention-offer-modal.tsx (1)
260-283: Implementation looks correct; consider defensive handling for edge case.The conditional rendering correctly hides the type selector when
cadence === 'yearly', aligning with the PR objective. For yearly offers, only the percentage discount fields will render sincegetDefaultStatesetstype: 'percent'for yearly cadence (line 71).Potential edge case: If an existing yearly offer was somehow stored with the
free_monthspattern (e.g., via API or legacy data),getRetentionOfferFormStatewould load it withtype: 'free_months'. In this scenario:
- The type selector remains hidden (yearly)
- The
free_monthsinput field renders (lines 330-344)- User has no way to switch to percentage discount
This may be unlikely in practice, but consider adding defensive enforcement in
getRetentionOfferFormStateto forcetype: 'percent'for yearly cadence:🛡️ Optional defensive fix in getRetentionOfferFormState
const getRetentionOfferFormState = (offer: Offer | null, cadence: 'monthly' | 'yearly' = 'monthly'): RetentionOfferFormState => { const defaultState = getDefaultState(cadence); if (!offer) { return defaultState; } const isFreeMonths = isFreeMonthsPattern(offer); + // For yearly cadence, force percent type since free_months is not supported + const resolvedType = cadence === 'yearly' ? 'percent' : (isFreeMonths ? 'free_months' : 'percent'); const isPercentOffer = offer.type === 'percent' && !isFreeMonths; const repeatingDurationInMonths = offer.duration === 'repeating' && offer.duration_in_months ? offer.duration_in_months : defaultState.durationInMonths; return { enabled: offer.status === 'active', displayTitle: offer.display_title || '', displayDescription: offer.display_description || '', - type: isFreeMonths ? 'free_months' : 'percent', + type: resolvedType, percentAmount: isPercentOffer ? offer.amount : defaultState.percentAmount, duration: isPercentOffer ? offer.duration : defaultState.duration, durationInMonths: repeatingDurationInMonths, freeMonths: isFreeMonths ? (offer.duration_in_months || defaultState.freeMonths) : defaultState.freeMonths }; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/admin-x-settings/src/components/settings/growth/offers/edit-retention-offer-modal.tsx` around lines 260 - 283, Ensure yearly offers cannot load with free_months by adding a defensive check in getRetentionOfferFormState: when cadence === 'yearly', override or coerce the loaded form state's type to 'percent' (mirroring getDefaultState behavior) so the UI (formState/type and dependent fields) always reflects a percent-only offer; update any state normalization there to set type = 'percent' and clear free_months-related fields if present.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@apps/admin-x-settings/src/components/settings/growth/offers/edit-retention-offer-modal.tsx`:
- Around line 260-283: Ensure yearly offers cannot load with free_months by
adding a defensive check in getRetentionOfferFormState: when cadence ===
'yearly', override or coerce the loaded form state's type to 'percent'
(mirroring getDefaultState behavior) so the UI (formState/type and dependent
fields) always reflects a percent-only offer; update any state normalization
there to set type = 'percent' and clear free_months-related fields if present.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/admin-x-settings/src/components/settings/growth/offers/edit-retention-offer-modal.tsx
ref https://linear.app/ghost/issue/BER-3364/use-a-stripe-coupon-instead-of-a-trial-for-free-month-offers
When
cadenceis yearly, the "Free month(s)" option is already excluded, leaving the type selector with only "Percentage discount" — a radio-style control with a single option. This hides the entire type selector container for yearly retention offers since there's no choice to make.