Commit 3239e63e authored by Vitaly Slobodin's avatar Vitaly Slobodin

Merge branch 'dz/337632-hint-invalid-input-for-addons-purchase' into 'master'

Improve UX for addons purchase

See merge request gitlab-org/gitlab!71582
parents e544abb4 b1b2a440
......@@ -105,6 +105,7 @@ export default {
name="quantity"
type="number"
:min="1"
:state="isValid"
data-qa-selector="quantity"
class="gl-w-15"
/>
......
......@@ -90,7 +90,7 @@ export default {
<div class="gl-display-flex gl-justify-content-space-between gl-font-weight-bold gl-my-3">
<div data-testid="selected-plan">
{{ selectedPlanText }}
<span v-if="quantity" data-testid="quantity">{{
<span v-if="hasPositiveQuantity" data-testid="quantity">{{
sprintf($options.i18n.quantity, { quantity })
}}</span>
</div>
......
......@@ -43,6 +43,7 @@ export const I18N_STORAGE_TOOLTIP_NOTE = s__(
export const I18N_DETAILS_STEP_TITLE = s__('Checkout|Purchase details');
export const I18N_DETAILS_NEXT_STEP_BUTTON_TEXT = s__('Checkout|Continue to billing');
export const I18N_DETAILS_FORMULA = s__('Checkout|x %{quantity} %{units} per pack =');
export const I18N_DETAILS_FORMULA_WITH_ALERT = s__('Checkout|x %{quantity} %{units} per pack');
export const I18N_SUMMARY_QUANTITY = s__('Checkout|(x%{quantity})');
export const I18N_SUMMARY_DATES = s__('Checkout|%{startDate} - %{endDate}');
......
......@@ -12,6 +12,7 @@ import {
I18N_CI_MINUTES_PRODUCT_LABEL,
I18N_CI_MINUTES_PRODUCT_UNIT,
I18N_DETAILS_FORMULA,
I18N_DETAILS_FORMULA_WITH_ALERT,
I18N_CI_MINUTES_FORMULA_TOTAL,
i18nCIMinutesSummaryTitle,
I18N_CI_MINUTES_SUMMARY_TOTAL,
......@@ -40,6 +41,7 @@ export default {
productLabel: I18N_CI_MINUTES_PRODUCT_LABEL,
productUnit: I18N_CI_MINUTES_PRODUCT_UNIT,
formula: I18N_DETAILS_FORMULA,
formulaWithAlert: I18N_DETAILS_FORMULA_WITH_ALERT,
formulaTotal: I18N_CI_MINUTES_FORMULA_TOTAL,
summaryTitle: i18nCIMinutesSummaryTitle,
summaryTotal: I18N_CI_MINUTES_SUMMARY_TOTAL,
......@@ -54,17 +56,26 @@ export default {
hasError: false,
};
},
computed: {
formulaText() {
return sprintf(this.$options.i18n.formula, {
methods: {
isQuantityValid(quantity) {
return Number.isFinite(quantity) && quantity > 0;
},
formulaText(quantity) {
const formulaText = this.isQuantityValid(quantity)
? this.$options.i18n.formula
: this.$options.i18n.formulaWithAlert;
return sprintf(formulaText, {
quantity: formatNumber(CI_MINUTES_PER_PACK),
units: this.$options.i18n.productUnit,
});
},
},
methods: {
formulaTotal(quantity) {
return sprintf(this.$options.i18n.formulaTotal, { totalCiMinutes: formatNumber(quantity) });
const total = sprintf(this.$options.i18n.formulaTotal, {
totalCiMinutes: formatNumber(quantity),
});
return this.isQuantityValid(quantity) ? total : '';
},
summaryTitle(quantity) {
return sprintf(this.$options.i18n.summaryTitle(quantity), { quantity });
......@@ -121,7 +132,7 @@ export default {
:alert-text="$options.i18n.alertText"
>
<template #formula="{ quantity }">
{{ formulaText }}
{{ formulaText(quantity) }}
<strong>{{ formulaTotal(quantity) }}</strong>
</template>
<template #summary-label="{ quantity }">
......
......@@ -13,6 +13,7 @@ import {
I18N_STORAGE_PRODUCT_UNIT,
I18N_DETAILS_FORMULA,
I18N_STORAGE_FORMULA_TOTAL,
I18N_DETAILS_FORMULA_WITH_ALERT,
i18nStorageSummaryTitle,
I18N_STORAGE_SUMMARY_TOTAL,
I18N_STORAGE_TITLE,
......@@ -43,6 +44,7 @@ export default {
productLabel: I18N_STORAGE_PRODUCT_LABEL,
productUnit: I18N_STORAGE_PRODUCT_UNIT,
formula: I18N_DETAILS_FORMULA,
formulaWithAlert: I18N_DETAILS_FORMULA_WITH_ALERT,
formulaTotal: I18N_STORAGE_FORMULA_TOTAL,
summaryTitle: i18nStorageSummaryTitle,
summaryTotal: I18N_STORAGE_SUMMARY_TOTAL,
......@@ -57,17 +59,24 @@ export default {
hasError: false,
};
},
computed: {
formulaText() {
return sprintf(this.$options.i18n.formula, {
methods: {
isQuantityValid(quantity) {
return Number.isFinite(quantity) && quantity > 0;
},
formulaText(quantity) {
const formulaText = this.isQuantityValid(quantity)
? this.$options.i18n.formula
: this.$options.i18n.formulaWithAlert;
return sprintf(formulaText, {
quantity: formatNumber(STORAGE_PER_PACK),
units: this.$options.i18n.productUnit,
});
},
},
methods: {
formulaTotal(quantity) {
return sprintf(this.$options.i18n.formulaTotal, { quantity: formatNumber(quantity) });
const total = sprintf(this.$options.i18n.formulaTotal, { quantity: formatNumber(quantity) });
return this.isQuantityValid(quantity) ? total : '';
},
summaryTitle(quantity) {
return sprintf(this.$options.i18n.summaryTitle(quantity), { quantity });
......@@ -122,7 +131,7 @@ export default {
:quantity-per-pack="$options.STORAGE_PER_PACK"
>
<template #formula="{ quantity }">
{{ formulaText }}
{{ formulaText(quantity) }}
<strong>{{ formulaTotal(quantity) }}</strong>
</template>
<template #summary-label="{ quantity }">
......
......@@ -73,7 +73,7 @@ describe('SummaryDetails', () => {
describe('when quantity is less or equal to zero', () => {
beforeEach(() => {
wrapper = createComponent({ quantity: 0 });
wrapper = createComponent({ quantity: -1 });
});
it('does not render quantity', () => {
......
......@@ -125,5 +125,13 @@ describe('App', () => {
expect(findSummaryLabel().text()).toBe('2 CI minute packs');
expect(findSummaryTotal().text()).toBe('Total minutes: 2,000');
});
it('are not shown if input is invalid', async () => {
const mockApollo = createMockApolloProvider({}, { quantity: -1 });
wrapper = createComponent(mockApollo);
await waitForPromises();
expect(findQuantityText().text()).toMatchInterpolatedText('x 1,000 minutes per pack');
});
});
});
......@@ -6784,6 +6784,9 @@ msgstr ""
msgid "Checkout|minutes"
msgstr ""
msgid "Checkout|x %{quantity} %{units} per pack"
msgstr ""
msgid "Checkout|x %{quantity} %{units} per pack ="
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment