Merge pull request #379 from Safelite/refactor/linting4
Linting of the iss-components
This commit is contained in:
commit
c4b06b6a69
18 changed files with 421 additions and 351 deletions
|
|
@ -143,13 +143,11 @@ describe('address-questions.vue', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
autocompleteElement.dispatchEvent(
|
autocompleteElement.dispatchEvent(new CustomEvent('place_changed', { detail: selectedPlace }));
|
||||||
new CustomEvent('place_changed', { detail: selectedPlace })
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
wrapper.vm.$nextTick(function () {
|
wrapper.vm.$nextTick(() => {
|
||||||
const addressModel = wrapper.vm.addressModel;
|
const { addressModel } = wrapper.vm;
|
||||||
expect(addressModel.streetAddress).toEqual('1234 Test Road');
|
expect(addressModel.streetAddress).toEqual('1234 Test Road');
|
||||||
expect(addressModel.city).toEqual('Columbus');
|
expect(addressModel.city).toEqual('Columbus');
|
||||||
expect(addressModel.state).toEqual('OH');
|
expect(addressModel.state).toEqual('OH');
|
||||||
|
|
@ -169,9 +167,9 @@ describe('address-questions.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
querySelectorFunction: function (query) {
|
querySelectorFunction(query) {
|
||||||
if (query == '.pac-container .pac-item') {
|
if (query == '.pac-container .pac-item') {
|
||||||
let element = document.createElement('div');
|
const element = document.createElement('div');
|
||||||
element.textContent = '123 Test Street';
|
element.textContent = '123 Test Street';
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
@ -222,8 +220,8 @@ describe('address-questions.vue', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
const noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
||||||
let verificationAlert = wrapper.findComponent({ ref: 'alertVerificationWarning' });
|
const verificationAlert = wrapper.findComponent({ ref: 'alertVerificationWarning' });
|
||||||
expect(noMatchAlert.exists()).toBeFalsy();
|
expect(noMatchAlert.exists()).toBeFalsy();
|
||||||
expect(verificationAlert.exists()).toBeFalsy();
|
expect(verificationAlert.exists()).toBeFalsy();
|
||||||
|
|
||||||
|
|
@ -235,7 +233,7 @@ describe('address-questions.vue', () => {
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
const addressModel = wrapper.vm.addressModel;
|
const { addressModel } = wrapper.vm;
|
||||||
expect(addressModel.streetAddress).toEqual('1234 Test Road');
|
expect(addressModel.streetAddress).toEqual('1234 Test Road');
|
||||||
expect(addressModel.city).toEqual('Columbus');
|
expect(addressModel.city).toEqual('Columbus');
|
||||||
expect(addressModel.state).toEqual('OH');
|
expect(addressModel.state).toEqual('OH');
|
||||||
|
|
@ -245,8 +243,7 @@ describe('address-questions.vue', () => {
|
||||||
|
|
||||||
describe('alerts', () => {
|
describe('alerts', () => {
|
||||||
const places = [null, { address_components: null }, undefined, {}];
|
const places = [null, { address_components: null }, undefined, {}];
|
||||||
test.each(places)(
|
test.each(places)('selected place/place properties is null => display verification alert',
|
||||||
'selected place/place properties is null => display verification alert',
|
|
||||||
async (place) => {
|
async (place) => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({});
|
const { wrapper } = setupMocks({});
|
||||||
|
|
@ -259,9 +256,7 @@ describe('address-questions.vue', () => {
|
||||||
const selectedPlace = place;
|
const selectedPlace = place;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
autocompleteElement.dispatchEvent(
|
autocompleteElement.dispatchEvent(new CustomEvent('place_changed', { detail: selectedPlace }));
|
||||||
new CustomEvent('place_changed', { detail: selectedPlace })
|
|
||||||
);
|
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -273,8 +268,7 @@ describe('address-questions.vue', () => {
|
||||||
|
|
||||||
const noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
const noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
||||||
expect(noMatchAlert.exists()).toBe(false);
|
expect(noMatchAlert.exists()).toBe(false);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
test('user enters address that yields no autocomplete results => show noMatch alert', async () => {
|
test('user enters address that yields no autocomplete results => show noMatch alert', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -318,9 +312,9 @@ describe('address-questions.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
querySelectorFunction: function (query) {
|
querySelectorFunction(query) {
|
||||||
if (query == '.pac-container .pac-item') {
|
if (query == '.pac-container .pac-item') {
|
||||||
let element = document.createElement('div');
|
const element = document.createElement('div');
|
||||||
element.textContent = '123 Test Street';
|
element.textContent = '123 Test Street';
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
@ -369,7 +363,7 @@ describe('address-questions.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
wrapper.vm.$nextTick(function () {
|
wrapper.vm.$nextTick(() => {
|
||||||
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
|
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
|
||||||
|
|
||||||
noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
||||||
|
|
@ -396,7 +390,7 @@ describe('address-questions.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
wrapper.vm.$nextTick(function () {
|
wrapper.vm.$nextTick(() => {
|
||||||
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
|
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
|
||||||
|
|
||||||
noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
||||||
|
|
@ -423,7 +417,7 @@ describe('address-questions.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
wrapper.vm.$nextTick(function () {
|
wrapper.vm.$nextTick(() => {
|
||||||
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
|
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
|
||||||
|
|
||||||
noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
||||||
|
|
@ -450,7 +444,7 @@ describe('address-questions.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
wrapper.vm.$nextTick(function () {
|
wrapper.vm.$nextTick(() => {
|
||||||
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
|
expect(wrapper.vm.displayNoMatchWarning).toBeFalsy();
|
||||||
|
|
||||||
noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' });
|
||||||
|
|
@ -461,6 +455,15 @@ describe('address-questions.vue', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param root0
|
||||||
|
* @param root0.mountOptions
|
||||||
|
* @param root0.props
|
||||||
|
* @param root0.isShallowMount
|
||||||
|
* @param root0.querySelectorFunction
|
||||||
|
* @param root0.geocoderResult
|
||||||
|
*/
|
||||||
function setupMocks({
|
function setupMocks({
|
||||||
mountOptions,
|
mountOptions,
|
||||||
props,
|
props,
|
||||||
|
|
@ -483,6 +486,10 @@ function setupMocks({
|
||||||
addListener: jest
|
addListener: jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation((element, eventName, callbackFunction) => {
|
.mockImplementation((element, eventName, callbackFunction) => {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
*/
|
||||||
function interceptedCallbackFunction(e) {
|
function interceptedCallbackFunction(e) {
|
||||||
callbackFunction(e.detail);
|
callbackFunction(e.detail);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<div role="application">
|
<div role="application">
|
||||||
<alert
|
<alert
|
||||||
ref="alertVerificationWarning"
|
|
||||||
v-if="displayVerificationWarning"
|
v-if="displayVerificationWarning"
|
||||||
|
ref="alertVerificationWarning"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
cmsWidgetName="AlertVerificationWarningWidget"
|
cmsWidgetName="AlertVerificationWarningWidget"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
v-bind:isDismissible="false" />
|
:isDismissible="false" />
|
||||||
<alert
|
<alert
|
||||||
ref="alertNoMatchWarning"
|
|
||||||
v-if="displayNoMatchWarning"
|
v-if="displayNoMatchWarning"
|
||||||
|
ref="alertNoMatchWarning"
|
||||||
class="mb-4 mt-4"
|
class="mb-4 mt-4"
|
||||||
cmsWidgetName="AlertNoMatchWarningWidget"
|
cmsWidgetName="AlertNoMatchWarningWidget"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
v-bind:isDismissible="false" />
|
:isDismissible="false" />
|
||||||
<div class="row mt-2 mb-4">
|
<div class="row mt-2 mb-4">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion
|
<textboxQuestion
|
||||||
id="streetAddressField"
|
id="streetAddressField"
|
||||||
cmsWidgetName="StreetAddressQuestionWidget"
|
|
||||||
v-model="addressModel.streetAddress"
|
|
||||||
ref="autocomplete"
|
ref="autocomplete"
|
||||||
|
v-model="addressModel.streetAddress"
|
||||||
|
cmsWidgetName="StreetAddressQuestionWidget"
|
||||||
inputId="autocomplete"
|
inputId="autocomplete"
|
||||||
placeholderText="Search"
|
placeholderText="Search"
|
||||||
aria-haspopup=""
|
aria-haspopup=""
|
||||||
|
|
@ -30,36 +30,43 @@
|
||||||
@keydown.enter.prevent />
|
@keydown.enter.prevent />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<transition name="fade" mode="out-in">
|
<transition
|
||||||
|
name="fade"
|
||||||
|
mode="out-in">
|
||||||
<div v-if="showAllFields">
|
<div v-if="showAllFields">
|
||||||
<div class="row mt-2 mb-4" v-if="includeStreetAddress2">
|
<div
|
||||||
|
v-if="includeStreetAddress2"
|
||||||
|
class="row mt-2 mb-4">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion
|
<textboxQuestion
|
||||||
ref="streetAddress2"
|
ref="streetAddress2"
|
||||||
cmsWidgetName="StreetAddress2QuestionWidget"
|
|
||||||
v-model="addressModel.streetAddress2"
|
v-model="addressModel.streetAddress2"
|
||||||
|
cmsWidgetName="StreetAddress2QuestionWidget"
|
||||||
aria-haspopup=""
|
aria-haspopup=""
|
||||||
inputId="streetAddress2Field"
|
inputId="streetAddress2Field" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-4" aria-live="polite">
|
<div
|
||||||
|
class="row mb-4"
|
||||||
|
aria-live="polite">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion
|
<textboxQuestion
|
||||||
cmsWidgetName="CityQuestionWidget"
|
|
||||||
v-model="addressModel.city"
|
|
||||||
ref="city"
|
ref="city"
|
||||||
|
v-model="addressModel.city"
|
||||||
|
cmsWidgetName="CityQuestionWidget"
|
||||||
inputId="cbf28188fdf2436688fd735915f7ee56"
|
inputId="cbf28188fdf2436688fd735915f7ee56"
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="city-required" />
|
validationRules="city-required" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-4" aria-live="polite">
|
<div
|
||||||
|
class="row mb-4"
|
||||||
|
aria-live="polite">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<dropdownQuestion
|
<dropdownQuestion
|
||||||
cmsWidgetName="StateQuestionWidget"
|
|
||||||
v-model="addressModel.state"
|
|
||||||
ref="state"
|
ref="state"
|
||||||
|
v-model="addressModel.state"
|
||||||
|
cmsWidgetName="StateQuestionWidget"
|
||||||
inputId="8fdf9dc2e13e430eb57529499dceb3eb"
|
inputId="8fdf9dc2e13e430eb57529499dceb3eb"
|
||||||
:options="stateOptions"
|
:options="stateOptions"
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
|
|
@ -67,9 +74,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion
|
<textboxQuestion
|
||||||
cmsWidgetName="ZipQuestionWidget"
|
|
||||||
v-model="addressModel.zipCode"
|
|
||||||
ref="zipCode"
|
ref="zipCode"
|
||||||
|
v-model="addressModel.zipCode"
|
||||||
|
cmsWidgetName="ZipQuestionWidget"
|
||||||
inputId="01a9a1c2de0b4c9da8e023c9ae3be498"
|
inputId="01a9a1c2de0b4c9da8e023c9ae3be498"
|
||||||
mask="#####"
|
mask="#####"
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
|
|
@ -101,7 +108,11 @@ defineRule('zip-code-format', regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.Z
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'address-questions',
|
name: 'address-questions',
|
||||||
emits: ['update:modelValue'], // The component emits an event
|
components: {
|
||||||
|
textboxQuestion,
|
||||||
|
dropdownQuestion,
|
||||||
|
alert
|
||||||
|
}, // The component emits an event
|
||||||
props: {
|
props: {
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|
@ -116,6 +127,7 @@ export default {
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
includeStreetAddress2: false
|
includeStreetAddress2: false
|
||||||
},
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
displayVerificationWarning: false,
|
displayVerificationWarning: false,
|
||||||
|
|
@ -133,29 +145,59 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
stateOptions: {
|
stateOptions: {
|
||||||
get: function () {
|
get() {
|
||||||
return states;
|
return states;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addressModel: {
|
addressModel: {
|
||||||
get: function () {
|
get() {
|
||||||
return this.modelValue;
|
return this.modelValue;
|
||||||
},
|
},
|
||||||
set: function (newValue) {
|
set(newValue) {
|
||||||
this.$emit('update:modelValue', newValue);
|
this.$emit('update:modelValue', newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
matchFound: {
|
||||||
|
handler(newValue) {
|
||||||
|
if (!newValue) {
|
||||||
|
this.displayNoMatchWarning = true;
|
||||||
|
|
||||||
|
this.addressModel.city = '';
|
||||||
|
this.addressModel.state = '';
|
||||||
|
this.addressModel.zipCode = '';
|
||||||
|
this.displayVerificationWarning = false;
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// Only deep watch the Address Model after a failed match
|
||||||
|
this.isAddressWatchActive = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addressModel: {
|
||||||
|
handler() {
|
||||||
|
if (this.isAddressWatchActive) {
|
||||||
|
this.displayNoMatchWarning = false;
|
||||||
|
this.isAddressWatchActive = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setupAddressLookup();
|
||||||
|
this.showAllFields = !!this.addressModel.streetAddress;
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setupAddressLookup() {
|
setupAddressLookup() {
|
||||||
const addressField1 = document.getElementById('autocomplete');
|
const addressField1 = document.getElementById('autocomplete');
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
const url = endpoints.GooglePlaces.url.replace('{apiKey}', applicationConfig.GOOGLE_PLACES_API_KEY)
|
const url = endpoints.GooglePlaces.url.replace('{apiKey}', applicationConfig.GOOGLE_PLACES_API_KEY);
|
||||||
|
|
||||||
this.$loadScript(
|
this.$loadScript(url)
|
||||||
url
|
|
||||||
)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Script is loaded, initialize the autocomplete textbox
|
// Script is loaded, initialize the autocomplete textbox
|
||||||
const autocomplete = new window.google.maps.places.Autocomplete(addressField1, {
|
const autocomplete = new window.google.maps.places.Autocomplete(addressField1, {
|
||||||
|
|
@ -165,11 +207,9 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Standard place_changed event handling
|
// Standard place_changed event handling
|
||||||
const autocompleteListener = window.google.maps.event.addListener(
|
const autocompleteListener = window.google.maps.event.addListener(autocomplete,
|
||||||
autocomplete,
|
|
||||||
'place_changed',
|
'place_changed',
|
||||||
fillInAddress
|
fillInAddress);
|
||||||
);
|
|
||||||
|
|
||||||
addressField1.addEventListener('focus', () => {
|
addressField1.addEventListener('focus', () => {
|
||||||
// Wrapping the addressField1 element in the Google Address Autocomplete object
|
// Wrapping the addressField1 element in the Google Address Autocomplete object
|
||||||
|
|
@ -196,13 +236,12 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
addressField1.blur();
|
addressField1.blur();
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addressField1.addEventListener('change', () => {
|
addressField1.addEventListener('change', () => {
|
||||||
// NOTE: The "place_changed" event of the autocomplete fires after this and will use either the address the user had chosen
|
// NOTE: The "place_changed" event of the autocomplete fires
|
||||||
|
// after this and will use either the address the user had chosen
|
||||||
// using either the down / up arrows or the address the user was hovering over when they pressed "Enter."
|
// using either the down / up arrows or the address the user was hovering over when they pressed "Enter."
|
||||||
|
|
||||||
// If a match has been previously found then do nothing
|
// If a match has been previously found then do nothing
|
||||||
|
|
@ -215,9 +254,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the address that the user clicked on (if any)
|
// Get the address that the user clicked on (if any)
|
||||||
const clickedAddress = document.querySelector(
|
const clickedAddress = document.querySelector('.pac-container .pac-item:hover');
|
||||||
'.pac-container .pac-item:hover'
|
|
||||||
);
|
|
||||||
|
|
||||||
// If the Street Address field changed without clicking (i.e. by pressing Tab, or clicking outside the field)
|
// If the Street Address field changed without clicking (i.e. by pressing Tab, or clicking outside the field)
|
||||||
if (clickedAddress === null) {
|
if (clickedAddress === null) {
|
||||||
|
|
@ -228,16 +265,14 @@ export default {
|
||||||
|
|
||||||
const firstResult = item.textContent;
|
const firstResult = item.textContent;
|
||||||
const geocoder = new window.google.maps.Geocoder();
|
const geocoder = new window.google.maps.Geocoder();
|
||||||
geocoder.geocode(
|
geocoder.geocode({
|
||||||
{
|
address: firstResult
|
||||||
address: firstResult
|
},
|
||||||
},
|
(results, status) => {
|
||||||
function (results, status) {
|
if (status === window.google.maps.GeocoderStatus.OK) {
|
||||||
if (status === window.google.maps.GeocoderStatus.OK) {
|
fillInAddress(results[0]);
|
||||||
fillInAddress(results[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
} else {
|
} else {
|
||||||
// No addresses found for the input
|
// No addresses found for the input
|
||||||
self.matchFound = false;
|
self.matchFound = false;
|
||||||
|
|
@ -245,6 +280,10 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param place
|
||||||
|
*/
|
||||||
function fillInAddress(place) {
|
function fillInAddress(place) {
|
||||||
if (!place) {
|
if (!place) {
|
||||||
place = autocomplete.getPlace();
|
place = autocomplete.getPlace();
|
||||||
|
|
@ -253,7 +292,7 @@ export default {
|
||||||
if (place && place.address_components) {
|
if (place && place.address_components) {
|
||||||
self.matchFound = true;
|
self.matchFound = true;
|
||||||
self.addressModel.streetAddress = '';
|
self.addressModel.streetAddress = '';
|
||||||
self.$nextTick(function () {
|
self.$nextTick(() => {
|
||||||
for (const component of place.address_components) {
|
for (const component of place.address_components) {
|
||||||
const componentType = component.types[0];
|
const componentType = component.types[0];
|
||||||
|
|
||||||
|
|
@ -264,7 +303,7 @@ export default {
|
||||||
}
|
}
|
||||||
case 'route': {
|
case 'route': {
|
||||||
self.addressModel.streetAddress
|
self.addressModel.streetAddress
|
||||||
+= ' ' + component.short_name;
|
+= ` ${component.short_name}`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'locality': {
|
case 'locality': {
|
||||||
|
|
@ -279,6 +318,7 @@ export default {
|
||||||
self.addressModel.zipCode = component.long_name;
|
self.addressModel.zipCode = component.long_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,48 +343,11 @@ export default {
|
||||||
console.log('Unable to load Google Places API script');
|
console.log('Unable to load Google Places API script');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.setupAddressLookup();
|
|
||||||
this.showAllFields = !!this.addressModel.streetAddress;
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
matchFound: {
|
|
||||||
handler(newValue) {
|
|
||||||
if (!newValue) {
|
|
||||||
this.displayNoMatchWarning = true;
|
|
||||||
|
|
||||||
this.addressModel.city = '';
|
|
||||||
this.addressModel.state = '';
|
|
||||||
this.addressModel.zipCode = '';
|
|
||||||
this.displayVerificationWarning = false;
|
|
||||||
|
|
||||||
this.$nextTick(function () {
|
|
||||||
// Only deep watch the Address Model after a failed match
|
|
||||||
this.isAddressWatchActive = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addressModel: {
|
|
||||||
handler() {
|
|
||||||
if (this.isAddressWatchActive) {
|
|
||||||
this.displayNoMatchWarning = false;
|
|
||||||
this.isAddressWatchActive = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
textboxQuestion,
|
|
||||||
dropdownQuestion,
|
|
||||||
alert
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
#streetAddressField {
|
#streetAddressField {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- Modal -->
|
<!-- Modal -->
|
||||||
<div
|
<div
|
||||||
|
:id="cmsWidgetName"
|
||||||
class="modal fade modal-component"
|
class="modal fade modal-component"
|
||||||
v-on="{ 'hidden.bs.modal': resetButtonStyle }"
|
|
||||||
:id="this.cmsWidgetName"
|
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
aria-labelledby="ModalComponentLabel"
|
aria-labelledby="ModalComponentLabel"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
v-on="{ 'hidden.bs.modal': resetButtonStyle }">
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
@ -18,27 +18,27 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<label
|
<label
|
||||||
:aria-label="this.ModalQuestionText"
|
:aria-label="ModalQuestionText"
|
||||||
class="form-label text-center w-100 mb-5 fw-bold"
|
class="form-label text-center w-100 mb-5 fw-bold"
|
||||||
v-html="this.ModalQuestionText"></label>
|
v-html="ModalQuestionText"></label>
|
||||||
</div>
|
</div>
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
|
v-model="selectedValue"
|
||||||
class="radioQuestion"
|
class="radioQuestion"
|
||||||
:questionText="questionText"
|
:questionText="questionText"
|
||||||
:answers="ModalSelectOptionAnswers"
|
:answers="ModalSelectOptionAnswers"
|
||||||
groupName="ChooseVehicleYear"
|
groupName="ChooseVehicleYear"
|
||||||
v-model="selectedValue"
|
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
isRequired />
|
isRequired />
|
||||||
<div class="modal-footer px-5 py-4">
|
<div class="modal-footer px-5 py-4">
|
||||||
<buttonMain
|
<buttonMain
|
||||||
|
ref="buttonMain"
|
||||||
class="w-100"
|
class="w-100"
|
||||||
isPrimary
|
isPrimary
|
||||||
ref="buttonMain"
|
|
||||||
suppressLoader
|
suppressLoader
|
||||||
:buttonText="ModalSelectButtonText"
|
:buttonText="ModalSelectButtonText"
|
||||||
@click-event="buttonClick"
|
data-bs-dismiss="modal"
|
||||||
data-bs-dismiss="modal" />
|
@click-event="buttonClick" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -50,7 +50,11 @@ import buttonMain from '@/ux-components/button-main/button-main';
|
||||||
import buttonQuestion from '@/digital-components/button-question/button-question';
|
import buttonQuestion from '@/digital-components/button-question/button-question';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'buttonQuestionModal',
|
name: 'button-question-modal',
|
||||||
|
components: {
|
||||||
|
buttonMain,
|
||||||
|
buttonQuestion
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
cmsWidgetName: String
|
cmsWidgetName: String
|
||||||
},
|
},
|
||||||
|
|
@ -69,15 +73,11 @@ export default {
|
||||||
resetButtonStyle() {
|
resetButtonStyle() {
|
||||||
this.$refs.buttonMain.resetButtonStyle();
|
this.$refs.buttonMain.resetButtonStyle();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
components: {
|
|
||||||
buttonMain,
|
|
||||||
buttonQuestion
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.modal {
|
.modal {
|
||||||
top: auto;
|
top: auto;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,22 @@
|
||||||
:modalId="ModalName"
|
:modalId="ModalName"
|
||||||
:footerButtonText="ModalCloseButtonText"
|
:footerButtonText="ModalCloseButtonText"
|
||||||
@footer-button-event="footerButtonClick">
|
@footer-button-event="footerButtonClick">
|
||||||
<img :src="ModalImage" class="mw-100 d-flex mx-auto mb-4" alt="" />
|
<img
|
||||||
<h5 class="mb-4" v-html="ModalHeadline"></h5>
|
:src="ModalImage"
|
||||||
<p class="fw-bold mb-2 subheader-text" v-html="ModalSubheadertext"></p>
|
class="mw-100 d-flex mx-auto mb-4"
|
||||||
<p class="mb-0" v-html="ModalBodyText"></p>
|
alt="" />
|
||||||
|
<h5
|
||||||
|
class="mb-4"
|
||||||
|
v-html="ModalHeadline"></h5>
|
||||||
|
<p
|
||||||
|
class="fw-bold mb-2 subheader-text"
|
||||||
|
v-html="ModalSubheadertext"></p>
|
||||||
|
<p
|
||||||
|
class="mb-0"
|
||||||
|
v-html="ModalBodyText"></p>
|
||||||
<p
|
<p
|
||||||
class="my-4 caption modal-sub-body"
|
|
||||||
v-if="ModalSubBodyText"
|
v-if="ModalSubBodyText"
|
||||||
|
class="my-4 caption modal-sub-body"
|
||||||
v-html="ModalSubBodyText"></p>
|
v-html="ModalSubBodyText"></p>
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -20,6 +29,9 @@ import modal from '@/digital-components/modal/modal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'content-group-modal',
|
name: 'content-group-modal',
|
||||||
|
components: {
|
||||||
|
modal
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
cmsWidgetName: String
|
cmsWidgetName: String
|
||||||
},
|
},
|
||||||
|
|
@ -54,14 +66,11 @@ export default {
|
||||||
footerButtonClick() {
|
footerButtonClick() {
|
||||||
this.$refs[this.ModalName].closeModal();
|
this.$refs[this.ModalName].closeModal();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
components: {
|
|
||||||
modal
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.modal {
|
.modal {
|
||||||
&.modal-component {
|
&.modal-component {
|
||||||
.modal-dialog {
|
.modal-dialog {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="isModalVisible" class="container-fluid modal-loader">
|
<div
|
||||||
|
v-if="isModalVisible"
|
||||||
|
class="container-fluid modal-loader">
|
||||||
<div class="row g-2 h-100 d-flex align-items-center">
|
<div class="row g-2 h-100 d-flex align-items-center">
|
||||||
<div class="container-fluid overflow-hidden">
|
<div class="container-fluid overflow-hidden">
|
||||||
<div class="row h-100">
|
<div class="row h-100">
|
||||||
<div class="col text-center tagbg mb-4">
|
<div class="col text-center tagbg mb-4">
|
||||||
<div class="spinner-border text-danger" role="status">
|
<div
|
||||||
|
class="spinner-border text-danger"
|
||||||
|
role="status">
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span class="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -52,7 +56,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Modal',
|
name: 'modal',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isModalVisible: false
|
isModalVisible: false
|
||||||
|
|
@ -63,23 +67,21 @@ export default {
|
||||||
// Display modal
|
// Display modal
|
||||||
this.isModalVisible = true;
|
this.isModalVisible = true;
|
||||||
// Force page reload on back button
|
// Force page reload on back button
|
||||||
window.addEventListener(
|
window.addEventListener('pageshow',
|
||||||
'pageshow',
|
(evt) => {
|
||||||
function (evt) {
|
|
||||||
if (evt.persisted) {
|
if (evt.persisted) {
|
||||||
setTimeout(function () {
|
setTimeout(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
false
|
false);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.modal-loader {
|
.modal-loader {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<input v-if="type == 'button'" type="button" class="nav-button" v-bind:value="text" v-on:click="navTo"/>
|
<input
|
||||||
<p v-else type="" class="nav-text" v-on:click="navTo">{{text}}</p>
|
v-if="type == 'button'"
|
||||||
|
type="button"
|
||||||
|
class="nav-button"
|
||||||
|
:value="text"
|
||||||
|
@click="navTo" />
|
||||||
|
<p
|
||||||
|
v-else
|
||||||
|
type=""
|
||||||
|
class="nav-text"
|
||||||
|
@click="navTo">
|
||||||
|
{{ text }}
|
||||||
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
name: 'navButton',
|
name: 'nav-button',
|
||||||
props: {
|
props: {
|
||||||
text: String,
|
text: String,
|
||||||
scenario: String,
|
scenario: String,
|
||||||
type: String
|
type: String
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
navTo(){
|
navTo() {
|
||||||
this.$router.navigate(this.scenario, this.$route)
|
this.$router.navigate(this.scenario, this.$route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
||||||
|
|
@ -202,15 +202,15 @@ function setupMocks() {
|
||||||
answerResult: '',
|
answerResult: '',
|
||||||
answerText: 'No',
|
answerText: 'No',
|
||||||
nextQuestionSequence: 3
|
nextQuestionSequence: 3
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
glassLocation: 'Windshield',
|
glassLocation: 'Windshield',
|
||||||
glassName: 'Single',
|
glassName: 'Single',
|
||||||
answerKey: 'Windshield-Single',
|
answerKey: 'Windshield-Single',
|
||||||
answerData: null
|
answerData: null
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -233,16 +233,16 @@ function setupMocks() {
|
||||||
'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?',
|
'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?',
|
||||||
selectedAnswerText: 'Yes',
|
selectedAnswerText: 'Yes',
|
||||||
questionNum: 2
|
questionNum: 2
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const mountOptions = getMountOptions({
|
const mountOptions = getMountOptions({
|
||||||
mixins: [baseMixin, vehicleQuestionsMixin]
|
mixins: [baseMixin, vehicleQuestionsMixin]
|
||||||
});
|
});
|
||||||
mountOptions['attachTo'] = document.body;
|
mountOptions.attachTo = document.body;
|
||||||
const wrapper = shallowMount(questionsPageLayout, mountOptions);
|
const wrapper = shallowMount(questionsPageLayout, mountOptions);
|
||||||
|
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@
|
||||||
<div class="row px-3">
|
<div class="row px-3">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="select-car-form rounded">
|
<div class="select-car-form rounded">
|
||||||
<vehicleBanner class="mt-2 mb-4" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
|
<vehicleBanner
|
||||||
|
class="mt-2 mb-4"
|
||||||
|
cmsWidgetName="VehicleBannerWidget"
|
||||||
|
:displayGenericVehicleImage="false" />
|
||||||
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
|
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
|
||||||
<alert
|
<alert
|
||||||
ref="alertFewMoreQuestions"
|
ref="alertFewMoreQuestions"
|
||||||
|
|
@ -16,25 +19,27 @@
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
:manualHeadline="alertFewMoreQuestionsHeader"
|
:manualHeadline="alertFewMoreQuestionsHeader"
|
||||||
:manualCopy="alertFewMoreQuestionsCopy"
|
:manualCopy="alertFewMoreQuestionsCopy"
|
||||||
v-bind:isDismissible="false"
|
:isDismissible="false"
|
||||||
class="mt-5"/>
|
class="mt-5" />
|
||||||
<div v-for="(questionsDatum, i) in questionsData" :key="questionsDatum.key">
|
<div
|
||||||
|
v-for="(questionsDatum, i) in questionsData"
|
||||||
|
:key="questionsDatum.key">
|
||||||
<questionChain
|
<questionChain
|
||||||
ref="questionChain"
|
v-if="showThisQuestionChain(questionsDatum, i)"
|
||||||
v-model="selectedAnswers[questionsDatum.answerKey]"
|
ref="questionChain"
|
||||||
:questionData="questionsDatum.questions"
|
v-model="selectedAnswers[questionsDatum.answerKey]"
|
||||||
:index="i"
|
:questionData="questionsDatum.questions"
|
||||||
v-if="showThisQuestionChain(questionsDatum, i)"
|
:index="i"
|
||||||
:answerKey="questionsDatum.answerKey"
|
:answerKey="questionsDatum.answerKey"
|
||||||
:validationRules="validationRules" />
|
:validationRules="validationRules" />
|
||||||
</div>
|
</div>
|
||||||
<siteFooter
|
<siteFooter
|
||||||
class="mt-5"
|
ref="siteFooter"
|
||||||
ref="siteFooter"
|
class="mt-5"
|
||||||
cmsWidgetName="SiteFooterWidget"
|
cmsWidgetName="SiteFooterWidget"
|
||||||
:isForwardActionDisabled="!isMetaValid"
|
:isForwardActionDisabled="!isMetaValid"
|
||||||
@back-clicked="handleBackButtonAction"
|
@back-clicked="handleBackButtonAction"
|
||||||
@ForwardClicked="handleForwardButtonAction" />
|
@ForwardClicked="handleForwardButtonAction" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -56,6 +61,15 @@ import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'questions-page',
|
name: 'questions-page',
|
||||||
|
components: {
|
||||||
|
siteHeader,
|
||||||
|
vehicleBanner,
|
||||||
|
alert,
|
||||||
|
questionChain,
|
||||||
|
siteSubHeader,
|
||||||
|
siteFooter,
|
||||||
|
loadingModal
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
isMetaValid: Boolean,
|
isMetaValid: Boolean,
|
||||||
alertFewMoreQuestionsHeader: String,
|
alertFewMoreQuestionsHeader: String,
|
||||||
|
|
@ -65,6 +79,7 @@ export default {
|
||||||
modelValue: Object,
|
modelValue: Object,
|
||||||
index: Number
|
index: Number
|
||||||
},
|
},
|
||||||
|
emits: ['update:modelValue', 'forwardButtonAction', 'back-click'],
|
||||||
computed: {
|
computed: {
|
||||||
selectedAnswers: {
|
selectedAnswers: {
|
||||||
get() {
|
get() {
|
||||||
|
|
@ -92,20 +107,11 @@ export default {
|
||||||
showLoadingModal() {
|
showLoadingModal() {
|
||||||
this.$refs.loadingModal.showModal();
|
this.$refs.loadingModal.showModal();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
components: {
|
|
||||||
siteHeader,
|
|
||||||
vehicleBanner,
|
|
||||||
alert,
|
|
||||||
questionChain,
|
|
||||||
siteSubHeader,
|
|
||||||
siteFooter,
|
|
||||||
loadingModal
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.questions-page {
|
.questions-page {
|
||||||
.question-text {
|
.question-text {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,47 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<footer class="footer container-fluid g-5 px-0" id="infoBox">
|
<footer
|
||||||
|
id="infoBox"
|
||||||
|
class="footer container-fluid g-5 px-0">
|
||||||
<div class="row d-flex flex-row-reverse align-items-center vw-100 mx-0">
|
<div class="row d-flex flex-row-reverse align-items-center vw-100 mx-0">
|
||||||
<div class="col button-col d-flex px-0" id="stacked" >
|
<div
|
||||||
|
id="stacked"
|
||||||
|
class="col button-col d-flex px-0">
|
||||||
<buttonMain
|
<buttonMain
|
||||||
v-if="!isForwardButtonHidden"
|
v-if="!isForwardButtonHidden"
|
||||||
ref="buttonMain"
|
ref="buttonMain"
|
||||||
isPrimary
|
isPrimary
|
||||||
:buttonText="buttonText"
|
:buttonText="buttonText"
|
||||||
loaderColor="white"
|
loaderColor="white"
|
||||||
:class="(disableForwardAction || isForwardActionDisabled) && 'form-test-invalid'"
|
:class="(disableForwardAction || isForwardActionDisabled) && 'form-test-invalid'"
|
||||||
:aria-disabled="isForwardActionDisabled"
|
:aria-disabled="isForwardActionDisabled"
|
||||||
:isDisabled="isForwardActionDisabled"
|
:isDisabled="isForwardActionDisabled"
|
||||||
@click-event="buttonClick"
|
data-bs-target="#footerModal"
|
||||||
data-bs-target="#footerModal"
|
data-bs-dismiss="modal"
|
||||||
data-bs-dismiss="modal"
|
data-test-id="site-footer-main-button"
|
||||||
data-test-id="site-footer-main-button" />
|
@click-event="buttonClick" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isBackButtonHidden" class="col-auto link-col py-1 px-0 text-break">
|
<div
|
||||||
|
v-if="!isBackButtonHidden"
|
||||||
|
class="col-auto link-col py-1 px-0 text-break">
|
||||||
<textLink
|
<textLink
|
||||||
linkType="navigation"
|
linkType="navigation"
|
||||||
:text="backLink"
|
:text="backLink"
|
||||||
@click-event="linkClick"
|
href="javascript:void(0)"
|
||||||
href="javascript:void(0)"
|
data-bs-target="#footerModal"
|
||||||
data-bs-target="#footerModal"
|
data-bs-dismiss="modal"
|
||||||
data-bs-dismiss="modal"
|
data-test-id="site-footer-back-button"
|
||||||
data-test-id="site-footer-back-button" />
|
@click-event="linkClick" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<div class="footerImage" id="imgCity" v-if="footerImageURL" >
|
<div
|
||||||
<img id="siteFooterImage" :src="footerImageURL" />
|
v-if="footerImageURL"
|
||||||
|
id="imgCity"
|
||||||
|
class="footerImage">
|
||||||
|
<img
|
||||||
|
id="siteFooterImage"
|
||||||
|
:src="footerImageURL" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -38,21 +49,21 @@
|
||||||
<script>
|
<script>
|
||||||
import textLink from '@/ux-components/text-link/text-link';
|
import textLink from '@/ux-components/text-link/text-link';
|
||||||
import buttonMain from '@/ux-components/button-main/button-main';
|
import buttonMain from '@/ux-components/button-main/button-main';
|
||||||
import { issPageValues } from '@/router/router-constants/issPage-values'
|
import { issPageValues } from '@/router/router-constants/issPage-values';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'siteFooter',
|
name: 'site-footer',
|
||||||
emits: ['backClicked', 'forwardClicked'],
|
components: {
|
||||||
|
textLink,
|
||||||
|
buttonMain
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
isForwardActionDisabled: Boolean,
|
isForwardActionDisabled: Boolean,
|
||||||
isBackButtonHidden: { type: Boolean, default: false },
|
isBackButtonHidden: { type: Boolean, default: false },
|
||||||
isForwardButtonHidden: { type: Boolean, default: false },
|
isForwardButtonHidden: { type: Boolean, default: false },
|
||||||
cmsWidgetName: String
|
cmsWidgetName: String
|
||||||
},
|
},
|
||||||
components: {
|
emits: ['backClicked', 'forwardClicked'],
|
||||||
textLink,
|
|
||||||
buttonMain
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
paddingHeight: 0,
|
paddingHeight: 0,
|
||||||
|
|
@ -60,18 +71,6 @@ export default {
|
||||||
disableForwardAction: false
|
disableForwardAction: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
this.paddingHeight = this.includeFooterImage ? this.getFooterInfoBoxHeight() + 16 : this.getFooterInfoBoxHeight() + 24;
|
|
||||||
this.$nextTick(() => {
|
|
||||||
window.addEventListener('resize', this.onResize);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
window.removeEventListener('resize', this.onResize);
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
document.onkeydown = null;
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
backLink() {
|
backLink() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'BackButtonText');
|
return this.getCmsContent(this.cmsWidgetName, 'BackButtonText');
|
||||||
|
|
@ -86,9 +85,21 @@ export default {
|
||||||
},
|
},
|
||||||
includeFooterImage() {
|
includeFooterImage() {
|
||||||
const currentPageName = this.getPageNameByQueryString();
|
const currentPageName = this.getPageNameByQueryString();
|
||||||
return (currentPageName.toLowerCase() == issPageValues.WELCOME_PAGE);
|
return (currentPageName.toLowerCase() === issPageValues.WELCOME_PAGE);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.paddingHeight = this.includeFooterImage ? this.getFooterInfoBoxHeight() + 16 : this.getFooterInfoBoxHeight() + 24;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
window.addEventListener('resize', this.onResize);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
window.removeEventListener('resize', this.onResize);
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
document.onkeydown = null;
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onResize() {
|
onResize() {
|
||||||
this.paddingHeight = this.getFooterInfoBoxHeight();
|
this.paddingHeight = this.getFooterInfoBoxHeight();
|
||||||
|
|
@ -98,15 +109,11 @@ export default {
|
||||||
},
|
},
|
||||||
removeLoader() {
|
removeLoader() {
|
||||||
this.$refs.buttonMain.removeLoader();
|
this.$refs.buttonMain.removeLoader();
|
||||||
document.onkeydown = function (e) {
|
document.onkeydown = () => true;
|
||||||
return true;
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
buttonClick() {
|
buttonClick() {
|
||||||
// prevent keyboard input after button click
|
// prevent keyboard input after button click
|
||||||
document.onkeydown = function (e) {
|
document.onkeydown = () => false;
|
||||||
return false;
|
|
||||||
};
|
|
||||||
this.$emit('forwardClicked');
|
this.$emit('forwardClicked');
|
||||||
},
|
},
|
||||||
linkClick() {
|
linkClick() {
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="menu-modal-container">
|
<div class="menu-modal-container">
|
||||||
<button class="menu-button" type="button" :class="[isActive ? 'active' : '']" aria-label="Hamburger Menu (modal window)" @click="toggle()">
|
<button
|
||||||
|
class="menu-button"
|
||||||
|
type="button"
|
||||||
|
:class="[isActive ? 'active' : '']"
|
||||||
|
aria-label="Hamburger Menu (modal window)"
|
||||||
|
@click="toggle()">
|
||||||
<div class="bar1"></div>
|
<div class="bar1"></div>
|
||||||
<div class="bar2"></div>
|
<div class="bar2"></div>
|
||||||
<div class="bar3"></div>
|
<div class="bar3"></div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Modal -->
|
<!-- Modal -->
|
||||||
<div class="modal menu-modal fade" data-bs-backdrop="false" id="footerModal" tabindex="-1" aria-labelledby="footerModalLabel" aria-hidden="true">
|
<div
|
||||||
|
id="footerModal"
|
||||||
|
class="modal menu-modal fade"
|
||||||
|
data-bs-backdrop="false"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-labelledby="footerModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="menu-modal-container">
|
<div class="menu-modal-container">
|
||||||
<button class="menu-button" type="button" :class="[isActive ? 'active' : '']" aria-label="Hamburger Menu (modal window)" @click="toggle()">
|
<button
|
||||||
|
class="menu-button"
|
||||||
|
type="button"
|
||||||
|
:class="[isActive ? 'active' : '']"
|
||||||
|
aria-label="Hamburger Menu (modal window)"
|
||||||
|
@click="toggle()">
|
||||||
<div class="bar1"></div>
|
<div class="bar1"></div>
|
||||||
<div class="bar2"></div>
|
<div class="bar2"></div>
|
||||||
<div class="bar3"></div>
|
<div class="bar3"></div>
|
||||||
|
|
@ -18,40 +34,44 @@
|
||||||
<div class="modal-dialog modal-fullscreen">
|
<div class="modal-dialog modal-fullscreen">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header visually-hidden">
|
<div class="modal-header visually-hidden">
|
||||||
<h5 class="modal-title" id="footerModalLabel">Footer Navigation</h5>
|
<h5
|
||||||
|
id="footerModalLabel"
|
||||||
|
class="modal-title">
|
||||||
|
Footer Navigation
|
||||||
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body d-flex flex-column">
|
<div class="modal-body d-flex flex-column">
|
||||||
<textLink
|
<textLink
|
||||||
linkType="navigation"
|
linkType="navigation"
|
||||||
text="Terms of service"
|
text="Terms of service"
|
||||||
href="//www.safelite.com/terms-of-use"
|
href="//www.safelite.com/terms-of-use"
|
||||||
target="_blank" />
|
target="_blank" />
|
||||||
<textLink
|
<textLink
|
||||||
linkType="navigation"
|
linkType="navigation"
|
||||||
text="Your privacy choices"
|
text="Your privacy choices"
|
||||||
href="//www.safelite.com/privacy-center"
|
href="//www.safelite.com/privacy-center"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
<template v-slot:after-text>
|
<template #after-text>
|
||||||
<img
|
<img
|
||||||
class="ccpa-icon"
|
class="ccpa-icon"
|
||||||
data-id="ccpa-icon"
|
data-id="ccpa-icon"
|
||||||
src="~@/assets/img/icons/ccpa-icon.svg"
|
src="~@/assets/img/icons/ccpa-icon.svg"
|
||||||
alt="Your privacy choices" />
|
alt="Your privacy choices" />
|
||||||
</template>
|
</template>
|
||||||
</textLink>
|
</textLink>
|
||||||
<textLink
|
<textLink
|
||||||
linkType="navigation"
|
linkType="navigation"
|
||||||
text="Warranty"
|
text="Warranty"
|
||||||
href="//www.safelite.com/national-lifetime-warranty"
|
href="//www.safelite.com/national-lifetime-warranty"
|
||||||
target="_blank" />
|
target="_blank" />
|
||||||
<textLink
|
<textLink
|
||||||
linkType="navigation"
|
linkType="navigation"
|
||||||
text="Notice at collection"
|
text="Notice at collection"
|
||||||
href="https://www.safelite.com/ccpa-privacy-policy"
|
href="https://www.safelite.com/ccpa-privacy-policy"
|
||||||
target="_blank" />
|
target="_blank" />
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer d-flex justify-content-start">
|
<div class="modal-footer d-flex justify-content-start">
|
||||||
© {{new Date().getFullYear()}} Safelite Group
|
© {{ new Date().getFullYear() }} Safelite Group
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -63,7 +83,10 @@ import textLink from '@/ux-components/text-link/text-link';
|
||||||
import { Modal } from 'bootstrap';
|
import { Modal } from 'bootstrap';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'menuModal',
|
name: 'menu-modal',
|
||||||
|
components: {
|
||||||
|
textLink
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isActive: false,
|
isActive: false,
|
||||||
|
|
@ -88,11 +111,8 @@ export default {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
components: {
|
|
||||||
textLink
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import siteHeader from '@/iss-components/site-header/site-header';
|
import siteHeader from '@/iss-components/site-header/site-header';
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
import { useMainStore } from '@/store/';
|
|
||||||
|
|
||||||
describe('site-header', () => {
|
describe('site-header', () => {
|
||||||
test('renders the logo image', () => {
|
test('renders the logo image', () => {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="site-header d-flex justify-content-center align-items-center flex-column py-2" :style="logoBackgroundStyle">
|
<div
|
||||||
<img id="siteHeaderImage" class="img-fluid" :src="imageSrc" :alt="altText" />
|
class="site-header d-flex justify-content-center align-items-center flex-column py-2"
|
||||||
<menuModal/>
|
:style="logoBackgroundStyle">
|
||||||
|
<img
|
||||||
|
id="siteHeaderImage"
|
||||||
|
class="img-fluid"
|
||||||
|
:src="imageSrc"
|
||||||
|
:alt="altText" />
|
||||||
|
<menuModal />
|
||||||
</div>
|
</div>
|
||||||
<alert
|
<alert
|
||||||
v-if="displayGlobalAlert"
|
v-if="displayGlobalAlert"
|
||||||
class="position-absolute rounded-0 w-100 border-0 shadow-sm start-0"
|
class="position-absolute rounded-0 w-100 border-0 shadow-sm start-0"
|
||||||
cmsWidgetName="GlobalAlert"
|
cmsWidgetName="GlobalAlert"
|
||||||
:manualHeadline="globalAlertMessage.messageHeadline"
|
:manualHeadline="globalAlertMessage.messageHeadline"
|
||||||
:manualCopy="globalAlertMessage.messageCopy"
|
:manualCopy="globalAlertMessage.messageCopy"
|
||||||
:alertClass="globalAlertMessage.type"
|
:alertClass="globalAlertMessage.type"
|
||||||
v-bind:isDismissible="globalAlertMessage.isDismissible" />
|
:isDismissible="globalAlertMessage.isDismissible" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -22,7 +28,14 @@ import eventBus from '@/helpers/event-bus/event-bus';
|
||||||
import { globalEvents } from '@/constants/events';
|
import { globalEvents } from '@/constants/events';
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
name: 'siteHeader',
|
name: 'site-header',
|
||||||
|
components: {
|
||||||
|
menuModal,
|
||||||
|
alert
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
displayGlobalAlert: false,
|
displayGlobalAlert: false,
|
||||||
|
|
@ -35,9 +48,6 @@ export default ({
|
||||||
headerAnswers: null
|
headerAnswers: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
|
||||||
cmsWidgetName: String
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
imageSrc() {
|
imageSrc() {
|
||||||
return this.headerAnswers ? this.headerAnswers.AnswerImageUrl : '';
|
return this.headerAnswers ? this.headerAnswers.AnswerImageUrl : '';
|
||||||
|
|
@ -51,23 +61,12 @@ export default ({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
|
||||||
setupHeader() {
|
|
||||||
const answers = this.getCmsContent(this.cmsWidgetName, 'Answers');
|
|
||||||
if(Array.isArray(answers)) {
|
|
||||||
this.headerAnswers = answers.filter(x => x.AccountNumber == this.mainStore.issConfig.accountNumber)[0]
|
|
||||||
this.headerAnswers = !this.headerAnswers ? answers.filter(x => x.AccountNumber === '0')[0] : this.headerAnswers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(this.setupHeader);
|
this.$nextTick(this.setupHeader);
|
||||||
|
|
||||||
// Check if alert event is on the bus
|
// Check if alert event is on the bus
|
||||||
const alertEvent = eventBus.readAndPopEventFromBus(
|
const alertEvent = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT,
|
||||||
globalEvents.Categories.GLOBAL_ALERT,
|
globalEvents.SubCategories.PAGE_NOT_FOUND);
|
||||||
globalEvents.SubCategories.PAGE_NOT_FOUND
|
|
||||||
);
|
|
||||||
// If alert event is on the bus, then display the alert
|
// If alert event is on the bus, then display the alert
|
||||||
if (alertEvent !== undefined) {
|
if (alertEvent !== undefined) {
|
||||||
this.displayGlobalAlert = true;
|
this.displayGlobalAlert = true;
|
||||||
|
|
@ -77,17 +76,21 @@ export default ({
|
||||||
// load client customization overrides
|
// load client customization overrides
|
||||||
const clientOverrideClass = this.mainStore.issConfig.styleSheet.trim();
|
const clientOverrideClass = this.mainStore.issConfig.styleSheet.trim();
|
||||||
if (clientOverrideClass
|
if (clientOverrideClass
|
||||||
&& clientOverrideClass != ''
|
&& clientOverrideClass !== ''
|
||||||
&& !document.getElementsByTagName('body')[0].className.split(' ').includes(clientOverrideClass))
|
&& !document.getElementsByTagName('body')[0].className.split(' ').includes(clientOverrideClass)) {
|
||||||
{
|
document.getElementsByTagName('body')[0].className += ` ${clientOverrideClass}`;
|
||||||
document.getElementsByTagName('body')[0].className += ' ' + clientOverrideClass;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
methods: {
|
||||||
menuModal,
|
setupHeader() {
|
||||||
alert
|
const answers = this.getCmsContent(this.cmsWidgetName, 'Answers');
|
||||||
|
if (Array.isArray(answers)) {
|
||||||
|
this.headerAnswers = answers.filter((x) => x.AccountNumber == this.mainStore.issConfig.accountNumber)[0];
|
||||||
|
this.headerAnswers = !this.headerAnswers ? answers.filter((x) => x.AccountNumber === '0')[0] : this.headerAnswers;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
@click="handleClick"
|
|
||||||
class="back-button-wrapper"
|
class="back-button-wrapper"
|
||||||
:aria-label="backButtonAccessibleText"
|
:aria-label="backButtonAccessibleText"
|
||||||
>
|
@click="handleClick">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="34px"
|
width="34px"
|
||||||
height="30px"
|
height="30px"
|
||||||
viewBox="-2.2 -6 30 30"
|
viewBox="-2.2 -6 30 30">
|
||||||
>
|
|
||||||
<g id="Layer_3">
|
<g id="Layer_3">
|
||||||
<path
|
<path
|
||||||
class="outer"
|
class="outer"
|
||||||
fill="#FFFFFF"
|
fill="#FFFFFF"
|
||||||
d="M19.934-1.434h-8.486c-1.683,0-2.999,0.528-4.021,1.614L1.685,6.146C0.78,7.079,0.338,8.027,0.338,9.041
|
d="M19.934-1.434h-8.486c-1.683,0-2.999,0.528-4.021,1.614L1.685,6.146C0.78,7.079,0.338,8.027,0.338,9.041
|
||||||
c0,1.028,0.444,1.979,1.359,2.908l5.753,5.938c1.054,1.093,2.403,1.647,4.007,1.647l8.475,0.01c2.861,0,4.568-1.692,4.568-4.528
|
c0,1.028,0.444,1.979,1.359,2.908l5.753,5.938c1.054,1.093,2.403,1.647,4.007,1.647l8.475,0.01c2.861,0,4.568-1.692,4.568-4.528
|
||||||
V3.094C24.5,0.259,22.793-1.434,19.934-1.434L19.934-1.434z"
|
V3.094C24.5,0.259,22.793-1.434,19.934-1.434L19.934-1.434z" />
|
||||||
/>
|
|
||||||
</g>
|
</g>
|
||||||
<g id="Layer_2">
|
<g id="Layer_2">
|
||||||
<path
|
<path
|
||||||
|
|
@ -29,8 +26,7 @@
|
||||||
c0-0.215,0.078-0.42,0.235-0.566l2.861-2.861l-2.861-2.862c-0.156-0.156-0.234-0.352-0.234-0.566c0-0.458,0.362-0.801,0.801-0.801
|
c0-0.215,0.078-0.42,0.235-0.566l2.861-2.861l-2.861-2.862c-0.156-0.156-0.234-0.352-0.234-0.566c0-0.458,0.362-0.801,0.801-0.801
|
||||||
c0.224,0,0.41,0.069,0.556,0.225l2.881,2.872l2.891-2.881c0.166-0.166,0.353-0.234,0.566-0.234c0.439,0,0.801,0.352,0.801,0.801
|
c0.224,0,0.41,0.069,0.556,0.225l2.881,2.872l2.891-2.881c0.166-0.166,0.353-0.234,0.566-0.234c0.439,0,0.801,0.352,0.801,0.801
|
||||||
c0,0.225-0.078,0.4-0.234,0.576l-2.871,2.871l2.861,2.852c0.146,0.156,0.234,0.352,0.234,0.576c0,0.449-0.361,0.82-0.811,0.82
|
c0,0.225-0.078,0.4-0.234,0.576l-2.871,2.871l2.861,2.852c0.146,0.156,0.234,0.352,0.234,0.576c0,0.449-0.361,0.82-0.811,0.82
|
||||||
c-0.225,0-0.43-0.098-0.586-0.244l-2.852-2.871l-2.852,2.871C11.203,13.165,10.999,13.253,10.773,13.253z"
|
c-0.225,0-0.43-0.098-0.586-0.244l-2.852-2.871l-2.852,2.871C11.203,13.165,10.999,13.253,10.773,13.253z" />
|
||||||
/>
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -38,7 +34,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'buttonBack',
|
name: 'button-back',
|
||||||
props: {
|
props: {
|
||||||
backButtonAccessibleText: {
|
backButtonAccessibleText: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
@ -46,6 +42,7 @@ export default {
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
emits: ['click-event'],
|
||||||
methods: {
|
methods: {
|
||||||
handleClick() {
|
handleClick() {
|
||||||
this.$emit('click-event');
|
this.$emit('click-event');
|
||||||
|
|
@ -54,7 +51,7 @@ export default {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.back-button-wrapper {
|
.back-button-wrapper {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="d-flex align-items-center justify-content-center container-fluid overflow-hidden">
|
<div class="d-flex align-items-center justify-content-center container-fluid overflow-hidden">
|
||||||
<h5 class="text-center fw-normal mb-0 subheader-primary" :class="headerColor">
|
<h5
|
||||||
|
class="text-center fw-normal mb-0 subheader-primary"
|
||||||
|
:class="headerColor">
|
||||||
<span>
|
<span>
|
||||||
{{ content }}
|
{{ content }}
|
||||||
</span>
|
</span>
|
||||||
<buttonBack
|
<buttonBack
|
||||||
v-if="hasBackButton"
|
v-if="hasBackButton"
|
||||||
:backButtonAccessibleText="backButtonAccessibleText"
|
:backButtonAccessibleText="backButtonAccessibleText"
|
||||||
@click-event="clickEvent"
|
@click-event="clickEvent" />
|
||||||
/>
|
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="subheader-secondary d-flex align-items-center container-fluid overflow-hidden" :class="justifySubheader">
|
<div
|
||||||
<p class="fw-normal mb-0" :class="alternateFormatting">
|
class="subheader-secondary d-flex align-items-center container-fluid overflow-hidden"
|
||||||
|
:class="justifySubheader">
|
||||||
|
<p
|
||||||
|
class="fw-normal mb-0"
|
||||||
|
:class="alternateFormatting">
|
||||||
<span v-html="subText">
|
<span v-html="subText">
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -25,7 +30,8 @@
|
||||||
import buttonBack from '@/iss-components/site-sub-header/button-back/button-back';
|
import buttonBack from '@/iss-components/site-sub-header/button-back/button-back';
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
name: 'siteSubHeader',
|
name: 'site-sub-header',
|
||||||
|
components: { buttonBack },
|
||||||
props: {
|
props: {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
hasBackButton: Boolean,
|
hasBackButton: Boolean,
|
||||||
|
|
@ -33,41 +39,40 @@ export default ({
|
||||||
issContainingPage: String,
|
issContainingPage: String,
|
||||||
darkGraySubText: Boolean
|
darkGraySubText: Boolean
|
||||||
},
|
},
|
||||||
|
emits: ['click-event'],
|
||||||
computed: {
|
computed: {
|
||||||
content() {
|
content() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'SubHeaderText')
|
return this.getCmsContent(this.cmsWidgetName, 'SubHeaderText');
|
||||||
},
|
},
|
||||||
subText() {
|
subText() {
|
||||||
const subText = this.getCmsContent(this.cmsWidgetName, 'SecondaryText');
|
const subText = this.getCmsContent(this.cmsWidgetName, 'SecondaryText');
|
||||||
return subText ?? '';
|
return subText ?? '';
|
||||||
},
|
},
|
||||||
backButtonAccessibleText() {
|
backButtonAccessibleText() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'BackButtonAccessibleText')
|
return this.getCmsContent(this.cmsWidgetName, 'BackButtonAccessibleText');
|
||||||
},
|
},
|
||||||
headerColor() {
|
headerColor() {
|
||||||
return this.subText ? 'dark-header' : 'light-header';
|
return this.subText ? 'dark-header' : 'light-header';
|
||||||
},
|
},
|
||||||
justifySubheader() {
|
justifySubheader() {
|
||||||
return (this.justification?.toLowerCase() === 'left') ?
|
return (this.justification?.toLowerCase() === 'left')
|
||||||
'justify-content-left' :
|
? 'justify-content-left'
|
||||||
'justify-content-center';
|
: 'justify-content-center';
|
||||||
},
|
},
|
||||||
alternateFormatting() {
|
alternateFormatting() {
|
||||||
// override for service-packages unique style
|
// override for service-packages unique style
|
||||||
if (this.issContainingPage?.toLowerCase() === 'service-packages') {
|
if (this.issContainingPage?.toLowerCase() === 'service-packages') {
|
||||||
return 'service-packages-subtext mt-4 mb-2 px-5';
|
return 'service-packages-subtext mt-4 mb-2 px-5';
|
||||||
} else {
|
|
||||||
return this.darkGraySubText ? 'dark-gray' : 'light-gray';
|
|
||||||
}
|
}
|
||||||
|
return this.darkGraySubText ? 'dark-gray' : 'light-gray';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clickEvent() {
|
clickEvent() {
|
||||||
this.$emit('click-event');
|
this.$emit('click-event');
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
components: { buttonBack }
|
});
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import steeringTextModal from './steering-text';
|
import App from '@/App';
|
||||||
import { createApp } from 'vue';
|
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import App from '@/App.vue';
|
import { createApp } from 'vue';
|
||||||
|
import steeringTextModal from './steering-text';
|
||||||
|
|
||||||
describe('steering-text.vue', () => {
|
describe('steering-text.vue', () => {
|
||||||
test('Should display steering text from CMS for state MA', async () => {
|
test('Should display steering text from CMS for state MA', async () => {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<textBlock
|
<textBlock
|
||||||
cmsWidgetName="MASteeringText"
|
|
||||||
id="SteeringTextContent"
|
id="SteeringTextContent"
|
||||||
/>
|
cmsWidgetName="MASteeringText" />
|
||||||
<div>
|
<div>
|
||||||
<p class="small" v-if="isStateMA" v-html="MASteeringText" ></p>
|
<p
|
||||||
|
v-if="isStateMA"
|
||||||
|
class="small"
|
||||||
|
v-html="MASteeringText"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -14,20 +16,21 @@
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'steeringTextModal',
|
name: 'steering-text-modal',
|
||||||
|
setup() {
|
||||||
|
const mainStore = useMainStore();
|
||||||
|
return { mainStore };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
MASteeringText() {
|
MASteeringText() {
|
||||||
return this.getCmsContent('MASteeringText', 'BodyText');
|
return this.getCmsContent('MASteeringText', 'BodyText');
|
||||||
},
|
},
|
||||||
isStateMA() {
|
isStateMA() {
|
||||||
if (this.mainStore.order.customer.address.state=='MA') {
|
if (this.mainStore.order.customer.address.state === 'MA') {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const mainStore = useMainStore();
|
|
||||||
return { mainStore };
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import { vehicleCategories } from '@/constants/vehicle-categories.js';
|
import { vehicleCategories } from '@/constants/vehicle-categories.js';
|
||||||
import vehicleBanner from './vehicle-banner';
|
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia, mapStores } from 'pinia';
|
||||||
import { mapStores } from 'pinia';
|
|
||||||
import App from '@/App.vue';
|
import App from '@/App.vue';
|
||||||
|
import vehicleBanner from './vehicle-banner';
|
||||||
|
|
||||||
const cmsData = { VehicleBannerWidget:
|
const cmsData = { VehicleBannerWidget:
|
||||||
{
|
{
|
||||||
|
|
@ -16,8 +16,7 @@ const cmsData = { VehicleBannerWidget:
|
||||||
VanUnmatchedVehicleIcon: 'van-placeholder.jpg',
|
VanUnmatchedVehicleIcon: 'van-placeholder.jpg',
|
||||||
CommercialVanUnmatchedVehicleIcon: 'commercial-placeholder.jpg',
|
CommercialVanUnmatchedVehicleIcon: 'commercial-placeholder.jpg',
|
||||||
SuvUnmatchedVehicleIcon: 'suv-placeholder.jpg'
|
SuvUnmatchedVehicleIcon: 'suv-placeholder.jpg'
|
||||||
}
|
} };
|
||||||
}
|
|
||||||
|
|
||||||
const vueApp = createApp(App);
|
const vueApp = createApp(App);
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
|
|
@ -37,7 +36,7 @@ const mockMixin = {
|
||||||
return vehicleCategories;
|
return vehicleCategories;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
describe('vehicleBanner', () => {
|
describe('vehicleBanner', () => {
|
||||||
test('renders the blurrycar image when displayGenericVehicleImage is true', async () => {
|
test('renders the blurrycar image when displayGenericVehicleImage is true', async () => {
|
||||||
|
|
@ -81,7 +80,7 @@ describe('vehicleBanner', () => {
|
||||||
mixins: [mockMixin]
|
mixins: [mockMixin]
|
||||||
});
|
});
|
||||||
|
|
||||||
var iconUrl = wrapper.vm.vehicleImageToDisplay;
|
const iconUrl = wrapper.vm.vehicleImageToDisplay;
|
||||||
|
|
||||||
expect(iconUrl).toEqual('car-placeholder.jpg');
|
expect(iconUrl).toEqual('car-placeholder.jpg');
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
|
|
@ -106,7 +105,7 @@ describe('vehicleBanner', () => {
|
||||||
mixins: [mockMixin]
|
mixins: [mockMixin]
|
||||||
});
|
});
|
||||||
|
|
||||||
var vehicleIcon = wrapper.vm.getUnmatchedVehicleIcon();
|
const vehicleIcon = wrapper.vm.getUnmatchedVehicleIcon();
|
||||||
|
|
||||||
expect(vehicleIcon).toEqual(expectedIcon);
|
expect(vehicleIcon).toEqual(expectedIcon);
|
||||||
expect(wrapper.find('img').attributes('class')).toContain('vehicle-image');
|
expect(wrapper.find('img').attributes('class')).toContain('vehicle-image');
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
<img
|
<img
|
||||||
class="vehicle-image img-fluid"
|
class="vehicle-image img-fluid"
|
||||||
:src="vehicleImageToDisplay"
|
:src="vehicleImageToDisplay"
|
||||||
alt=""
|
alt="" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -24,7 +23,7 @@ export default {
|
||||||
return this.genericVehicleImage;
|
return this.genericVehicleImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageUrl = this.mainStore.order.vehicle.imageUrl;
|
const { imageUrl } = this.mainStore.order.vehicle;
|
||||||
if (!imageUrl || imageUrl === 'NULL') {
|
if (!imageUrl || imageUrl === 'NULL') {
|
||||||
return this.getUnmatchedVehicleIcon();
|
return this.getUnmatchedVehicleIcon();
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +51,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getUnmatchedVehicleIcon() {
|
getUnmatchedVehicleIcon() {
|
||||||
switch (this.mainStore.order.vehicle.category){
|
switch (this.mainStore.order.vehicle.category) {
|
||||||
case this.vehicleCategories.CAR:
|
case this.vehicleCategories.CAR:
|
||||||
return this.carUnmatchedVehicleIcon;
|
return this.carUnmatchedVehicleIcon;
|
||||||
case this.vehicleCategories.SUV:
|
case this.vehicleCategories.SUV:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue