Commit c76a06d2 authored by Angelo Gulina's avatar Angelo Gulina Committed by Mark Florian

Fix design inconsistency

Update copy and styles for CI Minutes purchase flow
parent dc25a083
......@@ -41,7 +41,7 @@ export default {
<template>
<div class="checkout gl-display-flex gl-flex-direction-column gl-align-items-center">
<div class="flash-container"></div>
<h2 class="gl-mt-6 gl-mb-7 gl-mb-lg-5">{{ $options.i18n.checkout }}</h2>
<h2 class="gl-align-self-start gl-mt-6 gl-mb-7 gl-mb-lg-5">{{ $options.i18n.checkout }}</h2>
<addon-purchase-details :plan="plan" />
<billing-address />
<payment-method />
......
......@@ -7,7 +7,7 @@ import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { GENERAL_ERROR_MESSAGE } from 'ee/vue_shared/purchase_flow/constants';
import createFlash from '~/flash';
import { sprintf, s__, formatNumber } from '~/locale';
import { n__, s__, sprintf, formatNumber } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
export default {
......@@ -45,14 +45,17 @@ export default {
return this.quantity * CI_MINUTES_PER_PACK;
},
summaryCiMinutesQuantityText() {
return sprintf(this.$options.i18n.summaryCiMinutesQuantity, {
quantity: this.quantity,
});
return n__('Checkout|%d CI minute pack', 'Checkout|%d CI minute packs', this.quantity);
},
ciMinutesQuantityText() {
return sprintf(this.$options.i18n.ciMinutesQuantityText, {
totalCiMinutes: formatNumber(this.totalCiMinutes),
});
return sprintf(
n__(
'Checkout|%{totalCiMinutes} CI minute',
'Checkout|%{totalCiMinutes} CI minutes',
this.totalCiMinutes,
),
{ totalCiMinutes: formatNumber(this.totalCiMinutes) },
);
},
summaryCiMinutesTotal() {
return sprintf(this.$options.i18n.summaryCiMinutesTotal, {
......@@ -77,13 +80,12 @@ export default {
i18n: {
stepTitle: s__('Checkout|Purchase details'),
nextStepButtonText: s__('Checkout|Continue to billing'),
ciMinutesPacksLabel: s__('Checkout|CI minute packs'),
ciMinutesLabel: s__('Checkout|CI minute pack'),
ciMinutesAlertText: s__(
"Checkout|CI minute packs are only used after you've used your subscription's monthly quota. The additional minutes will roll over month to month and are valid for one year.",
),
ciMinutesPacksQuantityFormula: s__('Checkout|x 1,000 minutes per pack = %{strong}'),
ciMinutesQuantityText: s__('Checkout|%{totalCiMinutes} CI minutes'),
summaryCiMinutesQuantity: s__('Checkout|%{quantity} CI minute packs'),
summaryCiMinutesTotal: s__('Checkout|Total minutes: %{quantity}'),
},
stepId: STEPS[0].id,
......@@ -101,8 +103,10 @@ export default {
<gl-alert variant="info" class="gl-mb-3" :dismissible="false">
{{ $options.i18n.ciMinutesAlertText }}
</gl-alert>
<label for="quantity">{{ $options.i18n.ciMinutesPacksLabel }}</label>
<div class="gl-display-flex gl-flex-direction-row gl-align-items-center">
<label class="gl-mt-3" for="quantity" data-testid="product-label">
{{ $options.i18n.ciMinutesLabel }}
</label>
<div class="gl-display-flex gl-flex-direction-row gl-align-items-center gl-mb-6">
<gl-form-input
ref="quantity"
v-model.number="quantityModel"
......
......@@ -64,9 +64,8 @@ export default {
},
},
i18n: {
selectedPlanText: s__('Checkout|%{selectedPlanText} plan'),
quantity: s__('Checkout|(x%{quantity})'),
pricePerUnitPerYear: s__('Checkout|$%{selectedPlanPrice} per pack per year'),
pricePerUnitPerYear: s__('Checkout|$%{selectedPlanPrice} per pack of 1,000 minutes'),
dates: s__('Checkout|%{startDate} - %{endDate}'),
subtotal: s__('Checkout|Subtotal'),
tax: s__('Checkout|Tax'),
......@@ -81,7 +80,7 @@ export default {
class="gl-display-flex gl-justify-content-space-between gl-font-weight-bold gl-mt-3 gl-mb-3"
>
<div data-testid="selected-plan">
{{ sprintf($options.i18n.selectedPlanText, { selectedPlanText }) }}
{{ selectedPlanText }}
<span v-if="quantity" data-testid="quantity">{{
sprintf($options.i18n.quantity, { quantity })
}}</span>
......
import { GlAlert } from '@gitlab/ui';
import { mount, createLocalVue } from '@vue/test-utils';
import { createLocalVue } from '@vue/test-utils';
import { merge } from 'lodash';
import { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import AddonPurchaseDetails from 'ee/subscriptions/buy_minutes/components/checkout/addon_purchase_details.vue';
import subscriptionsResolvers from 'ee/subscriptions/buy_minutes/graphql/resolvers';
import { STEPS } from 'ee/subscriptions/constants';
import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import purchaseFlowResolvers from 'ee/vue_shared/purchase_flow/graphql/resolvers';
import { stateData as initialStateData } from 'ee_jest/subscriptions/buy_minutes/mock_data';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
const localVue = createLocalVue();
localVue.use(VueApollo);
......@@ -20,21 +21,17 @@ describe('AddonPurchaseDetails', () => {
const createMockApolloProvider = (stateData = {}) => {
const mockApollo = createMockApollo([], resolvers);
const data = merge({}, initialStateData, stateData);
mockApollo.clients.defaultClient.cache.writeQuery({
query: stateQuery,
data,
});
return mockApollo;
};
const createComponent = (stateData = {}) => {
const apolloProvider = createMockApolloProvider(stateData);
return mount(AddonPurchaseDetails, {
wrapper = mountExtended(AddonPurchaseDetails, {
localVue,
apolloProvider,
stubs: {
......@@ -45,11 +42,13 @@ describe('AddonPurchaseDetails', () => {
const findQuantity = () => wrapper.findComponent({ ref: 'quantity' });
const findGlAlert = () => wrapper.findComponent(GlAlert);
const findCiMinutesQuantityText = () => wrapper.find('[data-testid="ci-minutes-quantity-text"]');
const findCiMinutesQuantityText = () => wrapper.findByTestId('ci-minutes-quantity-text');
const findProductLabel = () => wrapper.findByTestId('product-label');
const findSummaryLabel = () => wrapper.findComponent({ ref: 'summary-line-1' });
const isStepValid = () => wrapper.findComponent(Step).props('isValid');
beforeEach(() => {
wrapper = createComponent();
createComponent();
});
afterEach(() => {
......@@ -78,12 +77,40 @@ describe('AddonPurchaseDetails', () => {
});
it('is invalid when quantity is less than 1', async () => {
wrapper = createComponent({
createComponent({
subscription: { namespaceId: 483, quantity: 0 },
});
await nextTick();
expect(isStepValid()).toBe(false);
});
describe('labels', () => {
describe('when quantity is 1', () => {
it('shows the correct product label', () => {
expect(findProductLabel().text()).toBe('CI minute pack');
});
it('shows the correct summary label', () => {
createComponent({ activeStep: STEPS[1] });
expect(findSummaryLabel().text()).toBe('1 CI minute pack');
});
});
describe('when quantity is more than 1', () => {
const stateData = { subscription: { namespaceId: 483, quantity: 2 } };
it('shows the correct product label', () => {
createComponent(stateData);
expect(findProductLabel().text()).toBe('CI minute pack');
});
it('shows the correct summary label', () => {
createComponent({ ...stateData, activeStep: STEPS[1] });
expect(findSummaryLabel().text()).toBe('2 CI minute packs');
});
});
});
});
......@@ -40,13 +40,11 @@ describe('SummaryDetails', () => {
});
it('renders the plan name', () => {
expect(wrapper.findByTestId('selected-plan').text()).toMatchInterpolatedText(
'Test plan (x1)',
);
expect(wrapper.findByTestId('selected-plan').text()).toMatchInterpolatedText('Test (x1)');
});
it('renders the price per unit', () => {
expect(wrapper.findByTestId('price-per-unit').text()).toBe('$10 per pack per year');
expect(wrapper.findByTestId('price-per-unit').text()).toBe('$10 per pack of 1,000 minutes');
});
it('displays the total amount', () => {
......
......@@ -5,7 +5,7 @@ export const mockCiMinutesPlans = [
id: 'ciMinutesPackPlanId',
code: 'ci_minutes',
pricePerYear: 10,
name: '1000 CI minutes pack',
name: 'CI minutes pack',
__typename: 'Plan',
},
];
......
......@@ -6526,12 +6526,17 @@ msgstr ""
msgid "Checkout"
msgstr ""
msgid "Checkout|$%{selectedPlanPrice} per pack per year"
msgid "Checkout|$%{selectedPlanPrice} per pack of 1,000 minutes"
msgstr ""
msgid "Checkout|$%{selectedPlanPrice} per user per year"
msgstr ""
msgid "Checkout|%d CI minute pack"
msgid_plural "Checkout|%d CI minute packs"
msgstr[0] ""
msgstr[1] ""
msgid "Checkout|%{cardType} ending in %{lastFourDigits}"
msgstr ""
......@@ -6541,15 +6546,17 @@ msgstr ""
msgid "Checkout|%{name}'s GitLab subscription"
msgstr ""
msgid "Checkout|%{quantity} CI minute packs"
msgstr ""
msgid "Checkout|%{selectedPlanText} plan"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr ""
msgid "Checkout|%{totalCiMinutes} CI minute"
msgid_plural "Checkout|%{totalCiMinutes} CI minutes"
msgstr[0] ""
msgstr[1] ""
msgid "Checkout|%{totalCiMinutes} CI minutes"
msgstr ""
......@@ -6565,7 +6572,7 @@ msgstr ""
msgid "Checkout|Billing address"
msgstr ""
msgid "Checkout|CI minute packs"
msgid "Checkout|CI minute pack"
msgstr ""
msgid "Checkout|CI minute packs are only used after you've used your subscription's monthly quota. The additional minutes will roll over month to month and are valid for one year."
......
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