Skip to content

Commit 87361d7

Browse files
authored
Merge pull request #2883 from FromDoppler/fix/new-plan-selection-ui-adjustments
fix(new-plan-selection): ajustes UI, mensajes de plan actual y consistencia visual
2 parents e63f525 + 96077d4 commit 87361d7

6 files changed

Lines changed: 201 additions & 50 deletions

File tree

src/components/BuyProcess/NewPlanSelection/ContactsPlan/index.js

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,14 @@ export const ContactsPlan = InjectAppServices(
235235
appliedPromocode.toLowerCase() === savedPromocode.toLowerCase();
236236
const shouldShowLosePromotionWarning =
237237
!isTailoredPlan && isUpgradePlan && isAppliedPromocodeSameAsSaved;
238+
const shouldShowCurrentPlanWarning =
239+
!isFreeAccount &&
240+
sessionPlan?.plan?.planType === PLAN_TYPE.byContact &&
241+
isEqualPlan &&
242+
!isTailoredPlan;
238243
const shouldUseAdvisorCta = isTailoredPlan || shouldShowDowngradeWarning;
244+
const shouldHideSubscriptionAndPromocode =
245+
isTailoredPlan || shouldShowDowngradeWarning || shouldShowCurrentPlanWarning;
239246
const shouldDisablePaymentFrequency = !isFreeAccount && !keepControlsEnabled;
240247

241248
const stickyDiscountSummary = useMemo(() => {
@@ -352,37 +359,43 @@ export const ContactsPlan = InjectAppServices(
352359
</option>
353360
</select>
354361
</div>
355-
<div className="dp-new-plan-selection-payment-frequency">
356-
<PaymentFrequency
357-
paymentFrequenciesList={paymentFrequencies}
358-
onSelectPaymentFrequency={handlePaymentFrequencyChange}
359-
currentSubscriptionUser={sessionPlan.plan.planSubscription}
360-
disabled={shouldDisablePaymentFrequency}
361-
/>
362-
</div>
363-
<div className="dp-new-plan-selection-promocode">
364-
<Promocode
365-
allowPromocode={
366-
!selectedPaymentFrequency?.id || selectedPaymentFrequency?.applyPromo
367-
}
368-
selectedMarketingPlan={selectedPlan}
369-
amountDetailsData={amountDetailsData}
370-
selectedPaymentFrequency={selectedPaymentFrequency}
371-
callback={handlePromocodeApplied}
372-
hasPromocodeAppliedItem={Boolean(effectivePromocodeApplied?.promocode)}
373-
isArgentina={sessionPlan.locationCountry === 'ar'}
374-
isFreeAccount={isFreeAccount}
375-
disabledPromocode={false}
376-
handleRemovePromocodeApplied={handleRemovePromocodeApplied}
377-
currentPromocodeApplied={effectivePromocodeApplied}
378-
registerClearPromocodeInput={registerClearPromocodeInput}
379-
defaultPromocodeDismissed={defaultPromocodeDismissed}
380-
handleManualPromocodeIntervention={handleManualPromocodeIntervention}
381-
hideCanNotApplyMessage={
382-
shouldShowLosePromotionWarning || shouldShowDowngradeWarning || isTailoredPlan
383-
}
384-
/>
385-
</div>
362+
{!shouldHideSubscriptionAndPromocode && (
363+
<>
364+
<div className="dp-new-plan-selection-payment-frequency">
365+
<PaymentFrequency
366+
paymentFrequenciesList={paymentFrequencies}
367+
onSelectPaymentFrequency={handlePaymentFrequencyChange}
368+
currentSubscriptionUser={sessionPlan.plan.planSubscription}
369+
disabled={shouldDisablePaymentFrequency}
370+
/>
371+
</div>
372+
<div className="dp-new-plan-selection-promocode">
373+
<Promocode
374+
allowPromocode={
375+
!selectedPaymentFrequency?.id || selectedPaymentFrequency?.applyPromo
376+
}
377+
selectedMarketingPlan={selectedPlan}
378+
amountDetailsData={amountDetailsData}
379+
selectedPaymentFrequency={selectedPaymentFrequency}
380+
callback={handlePromocodeApplied}
381+
hasPromocodeAppliedItem={Boolean(effectivePromocodeApplied?.promocode)}
382+
isArgentina={sessionPlan.locationCountry === 'ar'}
383+
isFreeAccount={isFreeAccount}
384+
disabledPromocode={false}
385+
handleRemovePromocodeApplied={handleRemovePromocodeApplied}
386+
currentPromocodeApplied={effectivePromocodeApplied}
387+
registerClearPromocodeInput={registerClearPromocodeInput}
388+
defaultPromocodeDismissed={defaultPromocodeDismissed}
389+
handleManualPromocodeIntervention={handleManualPromocodeIntervention}
390+
hideCanNotApplyMessage={
391+
shouldShowLosePromotionWarning ||
392+
shouldShowDowngradeWarning ||
393+
isTailoredPlan
394+
}
395+
/>
396+
</div>
397+
</>
398+
)}
386399
{isMoreThan100kSelected && (
387400
<div
388401
className="dp-wrap-message dp-wrap-info dp-new-plan-selection-more-than-message"
@@ -391,15 +404,18 @@ export const ContactsPlan = InjectAppServices(
391404
<span className="dp-message-icon" />
392405
<div className="dp-content-message">
393406
<p>
394-
<FormattedMessage id="buy_process.new_plan_selection.more_than_100k_info_message" />
407+
<FormattedMessage
408+
id="buy_process.new_plan_selection.more_than_100k_info_message"
409+
values={{ br: <br />, bold: (chunks) => <b>{chunks}</b> }}
410+
/>
395411
</p>
412+
<Link
413+
to="/upgrade-suggestion-form"
414+
className="dp-new-plan-selection-more-than-link"
415+
>
416+
<FormattedMessage id="buy_process.new_plan_selection.more_than_100k_contact_link" />
417+
</Link>
396418
</div>
397-
<Link
398-
to="/upgrade-suggestion-form"
399-
className="dp-new-plan-selection-more-than-link"
400-
>
401-
<FormattedMessage id="buy_process.new_plan_selection.more_than_100k_contact_link" />
402-
</Link>
403419
</div>
404420
)}
405421
{shouldShowLosePromotionWarning && (
@@ -434,6 +450,19 @@ export const ContactsPlan = InjectAppServices(
434450
</div>
435451
</div>
436452
)}
453+
{shouldShowCurrentPlanWarning && (
454+
<div
455+
className="dp-wrap-message dp-wrap-info dp-new-plan-selection-more-than-message"
456+
data-testid="dp-contacts-current-plan-message"
457+
>
458+
<span className="dp-message-icon" />
459+
<div className="dp-content-message dp-content-full">
460+
<p>
461+
<FormattedMessage id="buy_process.new_plan_selection.contacts_current_plan_warning_message" />
462+
</p>
463+
</div>
464+
</div>
465+
)}
437466
</div>
438467
</div>
439468

@@ -503,6 +532,7 @@ export const ContactsPlan = InjectAppServices(
503532
<FormattedMessage
504533
id="buy_process.new_plan_selection.savings_text"
505534
values={{
535+
br: <br />,
506536
percentage: selectedDiscountPercentage,
507537
currency: 'US$',
508538
period: _(

src/components/BuyProcess/NewPlanSelection/EmailsPlan/index.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,12 @@ export const EmailsPlan = InjectAppServices(
161161
selectedEmailCapacity < currentSessionEmailCapacity));
162162
const shouldShowHighVolumeMessage = isMoreThan10mSelected;
163163
const shouldUseAdvisorCta = shouldShowDowngradeWarning || shouldShowHighVolumeMessage;
164-
const shouldShowPromocode = !shouldUseAdvisorCta;
164+
const shouldShowCurrentPlanWarning =
165+
!isFreeAccount &&
166+
sessionPlan?.plan?.planType === PLAN_TYPE.byEmail &&
167+
isEqualPlan &&
168+
!shouldUseAdvisorCta;
169+
const shouldShowPromocode = !shouldUseAdvisorCta && !shouldShowCurrentPlanWarning;
165170
const extraEmailPrice = selectedPlan?.extraEmailPrice ?? 0;
166171

167172
const stickyDiscountSummary = useMemo(() => {
@@ -327,6 +332,19 @@ export const EmailsPlan = InjectAppServices(
327332
</div>
328333
</div>
329334
)}
335+
{shouldShowCurrentPlanWarning && (
336+
<div
337+
className="dp-wrap-message dp-wrap-info dp-new-plan-selection-more-than-message"
338+
data-testid="dp-emails-current-plan-message"
339+
>
340+
<span className="dp-message-icon" />
341+
<div className="dp-content-message dp-content-full">
342+
<p>
343+
<FormattedMessage id="buy_process.new_plan_selection.contacts_current_plan_warning_message" />
344+
</p>
345+
</div>
346+
</div>
347+
)}
330348
</div>
331349
</div>
332350

src/components/BuyProcess/NewPlanSelection/index.styles.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ export const NewPlanSelectionStyled = styled.div`
367367
}
368368
369369
.dp-new-plan-selection-price .dp-button {
370+
margin-top: 10px;
370371
width: 250px;
371372
}
372373
@@ -644,7 +645,7 @@ export const NewPlanSelectionStyled = styled.div`
644645
}
645646
646647
.dp-new-plan-selection-included-features {
647-
margin: 28px auto 30px;
648+
margin: 44px auto 30px;
648649
width: 100%;
649650
}
650651
@@ -853,7 +854,7 @@ export const NewPlanSelectionStyled = styled.div`
853854
}
854855
855856
.dp-new-plan-selection-addons {
856-
margin: 34px auto 36px;
857+
margin: 34px auto 52px;
857858
}
858859
859860
.dp-new-plan-selection-addons-header {
@@ -886,6 +887,7 @@ export const NewPlanSelectionStyled = styled.div`
886887
display: flex;
887888
flex: 1 1 auto;
888889
gap: 18px;
890+
padding: 6px 8px 10px;
889891
}
890892
891893
.dp-new-plan-selection-addon-card {
@@ -894,6 +896,7 @@ export const NewPlanSelectionStyled = styled.div`
894896
flex: 0 0 calc((100% - 36px) / 3);
895897
margin-bottom: 0;
896898
min-height: 100%;
899+
padding: 24px 24px 20px;
897900
}
898901
899902
.dp-new-plan-selection-addon-card .card-title {
@@ -967,6 +970,14 @@ export const NewPlanSelectionStyled = styled.div`
967970
max-width: none;
968971
}
969972
973+
.dp-new-plan-selection-faq section {
974+
padding-top: 32px;
975+
}
976+
977+
.dp-new-plan-selection-faq .dp-title-faq {
978+
margin-top: 0;
979+
}
980+
970981
.dp-new-plan-selection-faq .dp-accordion li .dp-accordion-thumb {
971982
color: #333;
972983
font-weight: 400;

src/components/BuyProcess/NewPlanSelection/index.test.js

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ describe('NewPlanSelection component', () => {
613613
planType: PLAN_TYPE.byContact,
614614
isFreeAccount: false,
615615
planSubscription: 12,
616+
subscribersCount: 900,
616617
promotion: {
617618
idUserTypePlan: 10222,
618619
code: 'PROMOCODE_ANNUAL',
@@ -625,7 +626,9 @@ describe('NewPlanSelection component', () => {
625626

626627
const promocodeInput = within(getContactsPlanSection()).getByRole('textbox');
627628
expect(promocodeInput).toHaveValue('');
628-
expect(screen.queryByRole('link', { name: /Elegir Plan/i })).not.toBeInTheDocument();
629+
const choosePlanHref = screen.getByRole('link', { name: /Elegir Plan/i }).getAttribute('href');
630+
expect(choosePlanHref).not.toContain('PromoCode=');
631+
expect(choosePlanHref).not.toContain('promo-code=');
629632
});
630633

631634
it('should update selected contacts plan in checkout URL when contacts dropdown changes', async () => {
@@ -693,6 +696,30 @@ describe('NewPlanSelection component', () => {
693696
).toHaveAttribute('href', '/checkout/premium/monthly-deliveries?selected-plan=30223&buyType=1');
694697
});
695698

699+
it('should show current plan warning and hide promocode when selected byEmail plan equals current one', async () => {
700+
await renderNewPlanSelection(
701+
['/new-plan-selection'],
702+
{
703+
appSessionUser: {
704+
plan: {
705+
idPlan: 30223,
706+
planType: PLAN_TYPE.byEmail,
707+
isFreeAccount: false,
708+
planSubscription: 1,
709+
},
710+
},
711+
},
712+
{ useI18nKeysAsValues: true },
713+
);
714+
715+
expect(getEmailsSelect()).toHaveValue('1');
716+
expect(screen.getByTestId('dp-emails-current-plan-message')).toBeInTheDocument();
717+
expect(
718+
screen.getByText('buy_process.new_plan_selection.contacts_current_plan_warning_message'),
719+
).toBeInTheDocument();
720+
expect(within(getEmailsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument();
721+
});
722+
696723
it('should preselect the next contact plan when subscribers count is lower than current plan capacity and a higher plan exists', async () => {
697724
const contactPlansWithExtraLevel = [
698725
{
@@ -792,6 +819,34 @@ describe('NewPlanSelection component', () => {
792819
).toBeDisabled();
793820
});
794821

822+
it('should show current plan warning and hide subscription and promocode when selected plan equals current one', async () => {
823+
await renderNewPlanSelection(
824+
['/new-plan-selection'],
825+
{
826+
appSessionUser: {
827+
plan: {
828+
idPlan: 10223,
829+
planType: PLAN_TYPE.byContact,
830+
isFreeAccount: false,
831+
planSubscription: 1,
832+
subscribersCount: 1300,
833+
},
834+
},
835+
},
836+
{ useI18nKeysAsValues: true },
837+
);
838+
839+
expect(getContactsSelect()).toHaveValue('1');
840+
expect(screen.getByTestId('dp-contacts-current-plan-message')).toBeInTheDocument();
841+
expect(
842+
screen.getByText('buy_process.new_plan_selection.contacts_current_plan_warning_message'),
843+
).toBeInTheDocument();
844+
expect(
845+
within(getContactsPlanSection()).queryByRole('button', { name: /Mensual/i }),
846+
).not.toBeInTheDocument();
847+
expect(within(getContactsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument();
848+
});
849+
795850
it('should preselect a higher contact plan when subscribers count is greater than current plan capacity', async () => {
796851
await renderNewPlanSelection(['/new-plan-selection'], {
797852
appSessionUser: {
@@ -967,6 +1022,10 @@ describe('NewPlanSelection component', () => {
9671022
await waitFor(() =>
9681023
expect(screen.getByTestId('dp-contacts-downgrade-message')).toBeInTheDocument(),
9691024
);
1025+
expect(
1026+
within(getContactsPlanSection()).queryByRole('button', { name: /Mensual/i }),
1027+
).not.toBeInTheDocument();
1028+
expect(within(getContactsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument();
9701029
expect(
9711030
screen.getByText('buy_process.new_plan_selection.contacts_downgrade_warning_message'),
9721031
).toBeInTheDocument();
@@ -1135,10 +1194,11 @@ describe('NewPlanSelection component', () => {
11351194
},
11361195
});
11371196

1138-
const annualFrequencyButton = within(getContactsPlanSection()).getByRole('button', {
1139-
name: /Anual/i,
1140-
});
1141-
expect(annualFrequencyButton).toBeDisabled();
1197+
expect(screen.getByTestId('dp-contacts-current-plan-message')).toBeInTheDocument();
1198+
expect(
1199+
within(getContactsPlanSection()).queryByRole('button', { name: /Anual/i }),
1200+
).not.toBeInTheDocument();
1201+
expect(within(getContactsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument();
11421202
});
11431203

11441204
it('should render credits plan before contacts plan for users with current credit plan', async () => {
@@ -1195,6 +1255,10 @@ describe('NewPlanSelection component', () => {
11951255

11961256
const infoBanner = screen.getByTestId('dp-more-than-100k-message');
11971257
expect(infoBanner).toBeInTheDocument();
1258+
expect(
1259+
within(getContactsPlanSection()).queryByRole('button', { name: /Mensual/i }),
1260+
).not.toBeInTheDocument();
1261+
expect(within(getContactsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument();
11981262
expect(within(infoBanner).getByText(/base supera los 100k de Contactos/i)).toBeInTheDocument();
11991263
expect(
12001264
within(infoBanner).getByRole('link', { name: /cont[aá]ctanos|contact us/i }),
@@ -1431,4 +1495,29 @@ describe('NewPlanSelection component', () => {
14311495
within(getCreditsPlanSection()).getByText(/Incluye 5.000 Creditos extra/i),
14321496
).toBeInTheDocument();
14331497
});
1498+
1499+
it('should keep prepayment breakdown in a new line for quarterly, semiannual and annual frequencies', async () => {
1500+
await renderNewPlanSelection();
1501+
1502+
const contactsSection = getContactsPlanSection();
1503+
const scenarios = [
1504+
{ buttonName: /Trimestral/i, expectedText: '1 pago trimestral de' },
1505+
{ buttonName: /Semestral/i, expectedText: '1 pago semestral de' },
1506+
{ buttonName: /Anual/i, expectedText: '1 pago anual de' },
1507+
];
1508+
1509+
for (const scenario of scenarios) {
1510+
fireEvent.click(within(contactsSection).getByRole('button', { name: scenario.buttonName }));
1511+
await settleAsyncState();
1512+
1513+
await waitFor(() => {
1514+
const savingsElement = contactsSection.querySelector(
1515+
'.dp-new-plan-selection-price-detail .dp-new-plan-selection-savings',
1516+
);
1517+
expect(savingsElement).toBeInTheDocument();
1518+
expect(savingsElement.textContent.toLowerCase()).toContain(scenario.expectedText);
1519+
expect(savingsElement.querySelector('br')).toBeInTheDocument();
1520+
});
1521+
}
1522+
});
14341523
});

0 commit comments

Comments
 (0)