Commit 3510cbd9 authored by Doug Stull's avatar Doug Stull Committed by Phil Hughes

Add state/province selector to trials

- for canada and US

Changelog: added
EE: true
parent e3fd22d4
......@@ -16,6 +16,7 @@ import countriesQuery from 'ee/subscriptions/graphql/queries/countries.query.gra
import statesQuery from 'ee/subscriptions/graphql/queries/states.query.graphql';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import {
COUNTRIES_WITH_STATES_ALLOWED,
LEADS_COMPANY_NAME_LABEL,
LEADS_COMPANY_SIZE_LABEL,
LEADS_COUNTRY_LABEL,
......@@ -26,7 +27,6 @@ import {
companySizes,
} from 'ee/vue_shared/leads/constants';
import {
COUNTRIES_WITH_STATES_ALLOWED,
PQL_COMPANY_SIZE_PROMPT,
PQL_PHONE_DESCRIPTION,
PQL_STATE_LABEL,
......
......@@ -21,5 +21,3 @@ export const PQL_HAND_RAISE_ACTION_ERROR = s__(
export const PQL_HAND_RAISE_ACTION_SUCCESS = s__(
'PQL|Thank you for reaching out! Our sales team will get back to you soon.',
);
export const COUNTRIES_WITH_STATES_ALLOWED = ['US', 'CA'];
<script>
import { GlFormGroup, GlFormSelect } from '@gitlab/ui';
import countriesQuery from 'ee/subscriptions/graphql/queries/countries.query.graphql';
import { LEADS_COUNTRY_LABEL, LEADS_COUNTRY_PROMPT } from 'ee/vue_shared/leads/constants';
import statesQuery from 'ee/subscriptions/graphql/queries/states.query.graphql';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import {
COUNTRIES_WITH_STATES_ALLOWED,
LEADS_COUNTRY_LABEL,
LEADS_COUNTRY_PROMPT,
} from 'ee/vue_shared/leads/constants';
import { TRIAL_STATE_LABEL, TRIAL_STATE_PROMPT } from '../constants';
export default {
name: 'CountryOrRegionList',
name: 'CountryOrRegionSelector',
components: {
GlFormGroup,
GlFormSelect,
},
directives: {
autofocusonshow,
},
inject: ['user'],
data() {
return { ...this.user, countries: [] };
return { ...this.user, countries: [], states: [] };
},
i18n: {
countryLabel: LEADS_COUNTRY_LABEL,
countrySelectPrompt: LEADS_COUNTRY_PROMPT,
stateLabel: TRIAL_STATE_LABEL,
stateSelectPrompt: TRIAL_STATE_PROMPT,
},
computed: {
countryOptionsWithDefault() {
......@@ -27,16 +39,43 @@ export default {
...this.countries,
];
},
mustEnterState() {
return COUNTRIES_WITH_STATES_ALLOWED.includes(this.country);
},
showState() {
return !this.$apollo.loading.states && this.states && this.country && this.mustEnterState;
},
stateOptionsWithDefault() {
return [
{
name: this.$options.i18n.stateSelectPrompt,
id: null,
},
...this.states,
];
},
},
apollo: {
countries: {
query: countriesQuery,
},
states: {
query: statesQuery,
skip() {
return !this.country;
},
variables() {
return {
countryId: this.country,
};
},
},
},
};
</script>
<template>
<div>
<gl-form-group
v-if="!$apollo.loading.countries"
:label="$options.i18n.countryLabel"
......@@ -45,7 +84,7 @@ export default {
>
<gl-form-select
id="country"
:value="country"
v-model="country"
name="country"
:options="countryOptionsWithDefault"
value-field="id"
......@@ -55,4 +94,23 @@ export default {
required
/>
</gl-form-group>
<gl-form-group
v-if="showState"
:label="$options.i18n.stateLabel"
label-size="sm"
label-for="state"
>
<gl-form-select
id="state"
v-autofocusonshow
:value="state"
name="state"
:options="stateOptionsWithDefault"
value-field="id"
text-field="name"
data-testid="state"
required
/>
</gl-form-group>
</div>
</template>
......@@ -3,3 +3,5 @@ import { s__, __ } from '~/locale';
export const TRIAL_FORM_SUBMIT_TEXT = s__('Trial|Continue');
export const TRIAL_COMPANY_SIZE_PROMPT = __('Please select');
export const TRIAL_PHONE_DESCRIPTION = s__('Trial|Allowed characters: +, 0-9, -, and spaces.');
export const TRIAL_STATE_LABEL = __('State/Province');
export const TRIAL_STATE_PROMPT = __('Please select');
......@@ -12,6 +12,7 @@ export const initTrialCreateLeadForm = () => {
companyName,
companySize,
country,
state,
phoneNumber,
} = el.dataset;
......@@ -25,6 +26,7 @@ export const initTrialCreateLeadForm = () => {
companyName,
companySize: companySize || null,
country: country || null,
state: state || null,
phoneNumber,
},
submitPath,
......
......@@ -8,6 +8,8 @@ export const LEADS_PHONE_NUMBER_LABEL = __('Telephone number');
export const LEADS_COUNTRY_LABEL = __('Country');
export const LEADS_COUNTRY_PROMPT = __('Please select a country');
export const COUNTRIES_WITH_STATES_ALLOWED = ['US', 'CA'];
export const companySizes = Object.freeze([
{
name: '1 - 99',
......
......@@ -21,7 +21,7 @@ module EE
first_name: current_user.first_name,
last_name: current_user.last_name,
company_name: current_user.organization
}.merge(params.slice(:first_name, :last_name, :company_name, :company_size, :phone_number, :country).to_unsafe_h.symbolize_keys)
}.merge(params.slice(:first_name, :last_name, :company_name, :company_size, :phone_number, :country, :state).to_unsafe_h.symbolize_keys)
end
def should_ask_company_question?
......
......@@ -14,12 +14,15 @@ RSpec.describe 'Trial Capture Lead', :js do
end
context 'with valid company information' do
let(:country) { { id: 'US', name: 'United States of America' } }
let(:extra_trial_params) { { "state" => form_data.dig(:state, :id) } }
let(:form_data) do
{
phone_number: '+1 23 456-78-90',
company_size: '1 - 99',
company_name: 'GitLab',
country: { id: 'US', name: 'United States of America' }
country: country,
state: { id: 'CA', name: 'California' }
}
end
......@@ -38,7 +41,7 @@ RSpec.describe 'Trial Capture Lead', :js do
"gitlab_com_trial" => true,
"provider" => "gitlab",
"newsletter_segment" => user.email_opted_in
}
}.merge(extra_trial_params)
lead_params = {
trial_user: ActionController::Parameters.new(trial_user_params).permit!
......@@ -49,11 +52,13 @@ RSpec.describe 'Trial Capture Lead', :js do
end
end
context 'with state' do
it 'proceeds to the next step' do
fill_in 'company_name', with: form_data[:company_name]
select form_data[:company_size], from: 'company_size'
fill_in 'phone_number', with: form_data[:phone_number]
select form_data.dig(:country, :name), from: 'country'
select form_data.dig(:state, :name), from: 'state'
click_button 'Continue'
......@@ -62,6 +67,26 @@ RSpec.describe 'Trial Capture Lead', :js do
end
end
context 'without state' do
let(:country) { { id: 'AF', name: 'Afghanistan' } }
let(:extra_trial_params) { {} }
it 'proceeds to the next step' do
fill_in 'company_name', with: form_data[:company_name]
select form_data[:company_size], from: 'company_size'
fill_in 'phone_number', with: form_data[:phone_number]
select form_data.dig(:country, :name), from: 'country'
expect(page).not_to have_selector('[data-testid="state"]')
click_button 'Continue'
expect(page).not_to have_css('flash-container')
expect(current_path).to eq(select_trials_path)
end
end
end
context 'with phone number validations' do
before do
fill_in 'company_name', with: 'GitLab'
......
import VueApollo from 'vue-apollo';
import { createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import CountryOrRegionList from 'ee/trials/components/country_or_region_selector.vue';
import CountryOrRegionSelector from 'ee/trials/components/country_or_region_selector.vue';
import { countries, states } from '../../hand_raise_leads/components/mock_data';
import { formData } from './mock_data';
const localVue = createLocalVue();
localVue.use(VueApollo);
describe('CountryOrRegionList', () => {
describe('CountryOrRegionSelector', () => {
let wrapper;
const createComponent = ({ mountFunction = shallowMountExtended } = {}) => {
......@@ -17,10 +18,13 @@ describe('CountryOrRegionList', () => {
countries() {
return [{ id: 'US', name: 'United States' }];
},
states() {
return [{ countryId: 'US', id: 'CA', name: 'California' }];
},
},
};
return mountFunction(CountryOrRegionList, {
return mountFunction(CountryOrRegionSelector, {
localVue,
apolloProvider: createMockApollo([], mockResolvers),
provide: {
......@@ -43,14 +47,38 @@ describe('CountryOrRegionList', () => {
it.each`
testid | value
${'country'} | ${'US'}
${'state'} | ${'CA'}
`('has the default injected value for $testid', ({ testid, value }) => {
expect(findFormInput(testid).attributes('value')).toBe(value);
});
it('has the correct form input in the form content', () => {
const visibleFields = ['country'];
const visibleFields = ['country', 'state'];
visibleFields.forEach((f) => expect(wrapper.findByTestId(f).exists()).toBe(true));
});
});
describe.each`
country | display
${'US'} | ${true}
${'CA'} | ${true}
${'NL'} | ${false}
`('Country & State handling', ({ country, display }) => {
describe(`when provided country is set to ${country}`, () => {
beforeEach(() => {
wrapper = createComponent();
});
it(`should${display ? '' : ' not'} render the state`, async () => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ countries, states, country });
await wrapper.vm.$nextTick();
expect(findFormInput('state').exists()).toBe(display);
});
});
});
});
......@@ -6,4 +6,5 @@ export const formData = {
companySize: '1-99',
phoneNumber: '192919',
country: 'US',
state: 'CA',
};
......@@ -17,7 +17,8 @@ RSpec.describe EE::TrialHelper do
company_name: '_params_company_name_',
company_size: '_company_size_',
phone_number: '1234',
country: '_country_'
country: '_country_',
state: '_state_'
}
end
......
......@@ -34003,6 +34003,9 @@ msgstr ""
msgid "State your message to activate"
msgstr ""
msgid "State/Province"
msgstr ""
msgid "State/Province/City"
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