diff --git a/src/components/BuyProcess/NewPlanSelection/ContactsPlan/index.js b/src/components/BuyProcess/NewPlanSelection/ContactsPlan/index.js index 057498213..d6588e015 100644 --- a/src/components/BuyProcess/NewPlanSelection/ContactsPlan/index.js +++ b/src/components/BuyProcess/NewPlanSelection/ContactsPlan/index.js @@ -235,7 +235,14 @@ export const ContactsPlan = InjectAppServices( appliedPromocode.toLowerCase() === savedPromocode.toLowerCase(); const shouldShowLosePromotionWarning = !isTailoredPlan && isUpgradePlan && isAppliedPromocodeSameAsSaved; + const shouldShowCurrentPlanWarning = + !isFreeAccount && + sessionPlan?.plan?.planType === PLAN_TYPE.byContact && + isEqualPlan && + !isTailoredPlan; const shouldUseAdvisorCta = isTailoredPlan || shouldShowDowngradeWarning; + const shouldHideSubscriptionAndPromocode = + isTailoredPlan || shouldShowDowngradeWarning || shouldShowCurrentPlanWarning; const shouldDisablePaymentFrequency = !isFreeAccount && !keepControlsEnabled; const stickyDiscountSummary = useMemo(() => { @@ -352,37 +359,43 @@ export const ContactsPlan = InjectAppServices( -
- -
-
- -
+ {!shouldHideSubscriptionAndPromocode && ( + <> +
+ +
+
+ +
+ + )} {isMoreThan100kSelected && (

- + , bold: (chunks) => {chunks} }} + />

+ + +
- - -
)} {shouldShowLosePromotionWarning && ( @@ -434,6 +450,19 @@ export const ContactsPlan = InjectAppServices( )} + {shouldShowCurrentPlanWarning && ( +
+ +
+

+ +

+
+
+ )} @@ -503,6 +532,7 @@ export const ContactsPlan = InjectAppServices( , percentage: selectedDiscountPercentage, currency: 'US$', period: _( diff --git a/src/components/BuyProcess/NewPlanSelection/EmailsPlan/index.js b/src/components/BuyProcess/NewPlanSelection/EmailsPlan/index.js index fe82a5736..d4ce602a0 100644 --- a/src/components/BuyProcess/NewPlanSelection/EmailsPlan/index.js +++ b/src/components/BuyProcess/NewPlanSelection/EmailsPlan/index.js @@ -161,7 +161,12 @@ export const EmailsPlan = InjectAppServices( selectedEmailCapacity < currentSessionEmailCapacity)); const shouldShowHighVolumeMessage = isMoreThan10mSelected; const shouldUseAdvisorCta = shouldShowDowngradeWarning || shouldShowHighVolumeMessage; - const shouldShowPromocode = !shouldUseAdvisorCta; + const shouldShowCurrentPlanWarning = + !isFreeAccount && + sessionPlan?.plan?.planType === PLAN_TYPE.byEmail && + isEqualPlan && + !shouldUseAdvisorCta; + const shouldShowPromocode = !shouldUseAdvisorCta && !shouldShowCurrentPlanWarning; const extraEmailPrice = selectedPlan?.extraEmailPrice ?? 0; const stickyDiscountSummary = useMemo(() => { @@ -327,6 +332,19 @@ export const EmailsPlan = InjectAppServices( )} + {shouldShowCurrentPlanWarning && ( +
+ +
+

+ +

+
+
+ )} diff --git a/src/components/BuyProcess/NewPlanSelection/index.styles.js b/src/components/BuyProcess/NewPlanSelection/index.styles.js index 04b0098f6..487c12547 100644 --- a/src/components/BuyProcess/NewPlanSelection/index.styles.js +++ b/src/components/BuyProcess/NewPlanSelection/index.styles.js @@ -367,6 +367,7 @@ export const NewPlanSelectionStyled = styled.div` } .dp-new-plan-selection-price .dp-button { + margin-top: 10px; width: 250px; } @@ -644,7 +645,7 @@ export const NewPlanSelectionStyled = styled.div` } .dp-new-plan-selection-included-features { - margin: 28px auto 30px; + margin: 44px auto 30px; width: 100%; } @@ -853,7 +854,7 @@ export const NewPlanSelectionStyled = styled.div` } .dp-new-plan-selection-addons { - margin: 34px auto 36px; + margin: 34px auto 52px; } .dp-new-plan-selection-addons-header { @@ -886,6 +887,7 @@ export const NewPlanSelectionStyled = styled.div` display: flex; flex: 1 1 auto; gap: 18px; + padding: 6px 8px 10px; } .dp-new-plan-selection-addon-card { @@ -894,6 +896,7 @@ export const NewPlanSelectionStyled = styled.div` flex: 0 0 calc((100% - 36px) / 3); margin-bottom: 0; min-height: 100%; + padding: 24px 24px 20px; } .dp-new-plan-selection-addon-card .card-title { @@ -967,6 +970,14 @@ export const NewPlanSelectionStyled = styled.div` max-width: none; } + .dp-new-plan-selection-faq section { + padding-top: 32px; + } + + .dp-new-plan-selection-faq .dp-title-faq { + margin-top: 0; + } + .dp-new-plan-selection-faq .dp-accordion li .dp-accordion-thumb { color: #333; font-weight: 400; diff --git a/src/components/BuyProcess/NewPlanSelection/index.test.js b/src/components/BuyProcess/NewPlanSelection/index.test.js index 55e7260d0..f129d5634 100644 --- a/src/components/BuyProcess/NewPlanSelection/index.test.js +++ b/src/components/BuyProcess/NewPlanSelection/index.test.js @@ -613,6 +613,7 @@ describe('NewPlanSelection component', () => { planType: PLAN_TYPE.byContact, isFreeAccount: false, planSubscription: 12, + subscribersCount: 900, promotion: { idUserTypePlan: 10222, code: 'PROMOCODE_ANNUAL', @@ -625,7 +626,9 @@ describe('NewPlanSelection component', () => { const promocodeInput = within(getContactsPlanSection()).getByRole('textbox'); expect(promocodeInput).toHaveValue(''); - expect(screen.queryByRole('link', { name: /Elegir Plan/i })).not.toBeInTheDocument(); + const choosePlanHref = screen.getByRole('link', { name: /Elegir Plan/i }).getAttribute('href'); + expect(choosePlanHref).not.toContain('PromoCode='); + expect(choosePlanHref).not.toContain('promo-code='); }); it('should update selected contacts plan in checkout URL when contacts dropdown changes', async () => { @@ -693,6 +696,30 @@ describe('NewPlanSelection component', () => { ).toHaveAttribute('href', '/checkout/premium/monthly-deliveries?selected-plan=30223&buyType=1'); }); + it('should show current plan warning and hide promocode when selected byEmail plan equals current one', async () => { + await renderNewPlanSelection( + ['/new-plan-selection'], + { + appSessionUser: { + plan: { + idPlan: 30223, + planType: PLAN_TYPE.byEmail, + isFreeAccount: false, + planSubscription: 1, + }, + }, + }, + { useI18nKeysAsValues: true }, + ); + + expect(getEmailsSelect()).toHaveValue('1'); + expect(screen.getByTestId('dp-emails-current-plan-message')).toBeInTheDocument(); + expect( + screen.getByText('buy_process.new_plan_selection.contacts_current_plan_warning_message'), + ).toBeInTheDocument(); + expect(within(getEmailsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument(); + }); + it('should preselect the next contact plan when subscribers count is lower than current plan capacity and a higher plan exists', async () => { const contactPlansWithExtraLevel = [ { @@ -792,6 +819,34 @@ describe('NewPlanSelection component', () => { ).toBeDisabled(); }); + it('should show current plan warning and hide subscription and promocode when selected plan equals current one', async () => { + await renderNewPlanSelection( + ['/new-plan-selection'], + { + appSessionUser: { + plan: { + idPlan: 10223, + planType: PLAN_TYPE.byContact, + isFreeAccount: false, + planSubscription: 1, + subscribersCount: 1300, + }, + }, + }, + { useI18nKeysAsValues: true }, + ); + + expect(getContactsSelect()).toHaveValue('1'); + expect(screen.getByTestId('dp-contacts-current-plan-message')).toBeInTheDocument(); + expect( + screen.getByText('buy_process.new_plan_selection.contacts_current_plan_warning_message'), + ).toBeInTheDocument(); + expect( + within(getContactsPlanSection()).queryByRole('button', { name: /Mensual/i }), + ).not.toBeInTheDocument(); + expect(within(getContactsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument(); + }); + it('should preselect a higher contact plan when subscribers count is greater than current plan capacity', async () => { await renderNewPlanSelection(['/new-plan-selection'], { appSessionUser: { @@ -967,6 +1022,10 @@ describe('NewPlanSelection component', () => { await waitFor(() => expect(screen.getByTestId('dp-contacts-downgrade-message')).toBeInTheDocument(), ); + expect( + within(getContactsPlanSection()).queryByRole('button', { name: /Mensual/i }), + ).not.toBeInTheDocument(); + expect(within(getContactsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument(); expect( screen.getByText('buy_process.new_plan_selection.contacts_downgrade_warning_message'), ).toBeInTheDocument(); @@ -1135,10 +1194,11 @@ describe('NewPlanSelection component', () => { }, }); - const annualFrequencyButton = within(getContactsPlanSection()).getByRole('button', { - name: /Anual/i, - }); - expect(annualFrequencyButton).toBeDisabled(); + expect(screen.getByTestId('dp-contacts-current-plan-message')).toBeInTheDocument(); + expect( + within(getContactsPlanSection()).queryByRole('button', { name: /Anual/i }), + ).not.toBeInTheDocument(); + expect(within(getContactsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument(); }); it('should render credits plan before contacts plan for users with current credit plan', async () => { @@ -1195,6 +1255,10 @@ describe('NewPlanSelection component', () => { const infoBanner = screen.getByTestId('dp-more-than-100k-message'); expect(infoBanner).toBeInTheDocument(); + expect( + within(getContactsPlanSection()).queryByRole('button', { name: /Mensual/i }), + ).not.toBeInTheDocument(); + expect(within(getContactsPlanSection()).queryByRole('textbox')).not.toBeInTheDocument(); expect(within(infoBanner).getByText(/base supera los 100k de Contactos/i)).toBeInTheDocument(); expect( within(infoBanner).getByRole('link', { name: /cont[aá]ctanos|contact us/i }), @@ -1431,4 +1495,29 @@ describe('NewPlanSelection component', () => { within(getCreditsPlanSection()).getByText(/Incluye 5.000 Creditos extra/i), ).toBeInTheDocument(); }); + + it('should keep prepayment breakdown in a new line for quarterly, semiannual and annual frequencies', async () => { + await renderNewPlanSelection(); + + const contactsSection = getContactsPlanSection(); + const scenarios = [ + { buttonName: /Trimestral/i, expectedText: '1 pago trimestral de' }, + { buttonName: /Semestral/i, expectedText: '1 pago semestral de' }, + { buttonName: /Anual/i, expectedText: '1 pago anual de' }, + ]; + + for (const scenario of scenarios) { + fireEvent.click(within(contactsSection).getByRole('button', { name: scenario.buttonName })); + await settleAsyncState(); + + await waitFor(() => { + const savingsElement = contactsSection.querySelector( + '.dp-new-plan-selection-price-detail .dp-new-plan-selection-savings', + ); + expect(savingsElement).toBeInTheDocument(); + expect(savingsElement.textContent.toLowerCase()).toContain(scenario.expectedText); + expect(savingsElement.querySelector('br')).toBeInTheDocument(); + }); + } + }); }); diff --git a/src/i18n/en.js b/src/i18n/en.js index 21d769f3f..f644073dc 100644 --- a/src/i18n/en.js +++ b/src/i18n/en.js @@ -173,6 +173,7 @@ other {}}}}}}}}}} buy_credits: 'Buy Credits', choose_plan: 'Choose Plan', contact_advisor_cta: 'Contact an Advisor', + contacts_current_plan_warning_message: 'You cannot select this Plan because it is your current one.', contacts_downgrade_warning_message: 'Need to reduce contacts?{br}If you want to switch to a smaller Contacts Plan, contact us so we can advise you.', contacts_label: 'How many Contacts do you have?', contacts_option: '{contacts}', @@ -218,7 +219,7 @@ other {}}}}}}}}}} }, month_period: 'month', more_than_100k_contact_link: 'CONTACT US', - more_than_100k_info_message: 'Do you exceed 100k contacts? The Email Plan gives you unlimited Contacts and a lower cost per send. Talk to our advisors and build a tailored Plan.', + more_than_100k_info_message: 'Do you exceed 100k contacts?{br}The Email Plan gives you unlimited Contacts and a lower cost per send. Talk to our advisors and build a tailored Plan.', payment_period_half_yearly: 'semiannual', payment_period_monthly: 'monthly', payment_period_quarterly: 'quarterly', @@ -227,7 +228,7 @@ other {}}}}}}}}}} price_label: 'Price', promocode_savings_text: 'You save {percentage}% for {months, plural, one {# month} other {# months}}', promocode_savings_text_without_months: 'You save {percentage}%', - savings_text: 'You save {percentage}% with 1 {period} payment of {currency}{total}', + savings_text: 'You save {percentage}% with{br}1 {period} payment of {currency}{total}', single_payment_period: 'one-time payment', sticky_contacts_subtitle: 'Up to {contacts} Contacts + Unlimited emails', sticky_custom_cta: 'Consult with Doppler Team', diff --git a/src/i18n/es.js b/src/i18n/es.js index 2de781357..ad0dd08a4 100644 --- a/src/i18n/es.js +++ b/src/i18n/es.js @@ -174,6 +174,7 @@ other {}}}}}}}}}} buy_credits: 'Comprar Creditos', choose_plan: 'Elegir Plan', contact_advisor_cta: 'Contactar a Asesor', + contacts_current_plan_warning_message: 'No puedes seleccionar este Plan porque es el que posees actualmente.', contacts_downgrade_warning_message: '¿Necesitas disminuir los contactos?{br}Si deseas pasar a un Plan con menos Contactos, contáctanos para que podamos asesorarte.', contacts_label: '¿Cuántos Contactos tienes?', contacts_option: '{contacts}', @@ -219,7 +220,8 @@ other {}}}}}}}}}} }, month_period: 'mes', more_than_100k_contact_link: 'CONTÁCTANOS', - more_than_100k_info_message: '¿Tu base supera los 100k de Contactos? El Plan Envíos te da Contactos ilimitados y el costo por Envío más bajo. Habla con nuestros asesores y arma el Plan personalizado.', + more_than_100k_info_message: + '¿Tu base supera los 100k de Contactos?{br}El Plan Envíos te da Contactos ilimitados y el costo por Envío más bajo. Habla con nuestros asesores y arma el Plan personalizado.', payment_period_half_yearly: 'semestral', payment_period_monthly: 'mensual', payment_period_quarterly: 'trimestral', @@ -228,7 +230,7 @@ other {}}}}}}}}}} price_label: 'Precio', promocode_savings_text: 'Ahorras {percentage}% durante {months, plural, one {# mes} other {# meses}}', promocode_savings_text_without_months: 'Ahorras {percentage}%', - savings_text: 'Ahorras {percentage}% realizando 1 pago {period} de {currency}{total}', + savings_text: 'Ahorras {percentage}% realizando{br}1 pago {period} de {currency}{total}', single_payment_period: 'pago unico', sticky_contacts_subtitle: 'Hasta {contacts} Contactos + Envios ilimitados', sticky_custom_cta: 'Consultar con Doppler Team',