Merge branch 'develop' into feature/CSR-347
This commit is contained in:
commit
ee7f4843c8
49 changed files with 810 additions and 377 deletions
|
|
@ -128,3 +128,44 @@ stages:
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
||||||
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
||||||
cfDistributionId: $(cfDistributionId)
|
cfDistributionId: $(cfDistributionId)
|
||||||
|
|
||||||
|
# Prod Build/Deploy
|
||||||
|
- stage: Prod
|
||||||
|
condition: eq(variables['Build.SourceBranch'], variables['prod-branch'] )
|
||||||
|
variables:
|
||||||
|
- group: FixMyGlassProd
|
||||||
|
jobs:
|
||||||
|
- deployment: prodBuildDeployment
|
||||||
|
displayName: Build and Deploy FMG - Prod
|
||||||
|
environment: digitalCloud-prod
|
||||||
|
container: node
|
||||||
|
workspace:
|
||||||
|
clean: all
|
||||||
|
strategy:
|
||||||
|
runOnce:
|
||||||
|
deploy:
|
||||||
|
steps:
|
||||||
|
- checkout: self
|
||||||
|
clean: true
|
||||||
|
- template: templates/digital/step-build-vue.yml@AzureDevOps
|
||||||
|
parameters:
|
||||||
|
buildOutputDir: dist
|
||||||
|
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
|
||||||
|
parameters:
|
||||||
|
artifactName: vueDist
|
||||||
|
awsProfile: $(prodDeploymentProfile)
|
||||||
|
outputPath: /fmg/
|
||||||
|
deployBuckets:
|
||||||
|
safelite-prod-fmg-us-east-1:
|
||||||
|
clearFolder: true
|
||||||
|
deployFolder: ''
|
||||||
|
region: us-east-1
|
||||||
|
appDeployVariables:
|
||||||
|
__VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__)
|
||||||
|
__VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__)
|
||||||
|
__VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__)
|
||||||
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
||||||
|
indexDeployVariables:
|
||||||
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
||||||
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
||||||
|
cfDistributionId: $(cfDistributionId)
|
||||||
|
|
@ -27,13 +27,14 @@ module.exports = {
|
||||||
"!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue",
|
"!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue",
|
||||||
"!src/common-components/dropdown-question/dropdown-question.vue",
|
"!src/common-components/dropdown-question/dropdown-question.vue",
|
||||||
"!src/common-components/textbox-question/textbox-question.vue",
|
"!src/common-components/textbox-question/textbox-question.vue",
|
||||||
|
"!src/ux-components/alert\alert.vue",
|
||||||
"!src/helpers/validation-rules.js",
|
"!src/helpers/validation-rules.js",
|
||||||
// END
|
// END
|
||||||
], // ! means exclude from coverage.
|
], // ! means exclude from coverage.
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
statements: 85,
|
statements: 84,
|
||||||
// Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90
|
// Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<transition :duration="{ enter: 800, leave: 300 }" name="route-fade" mode="out-in">
|
<transition :duration="{ enter: 200, leave: 200 }" name="route-fade" mode="out-in">
|
||||||
|
<!-- The above durations should be kept in sync with the global css class "fade-on-route-transition" -->
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
|
|
||||||
1
src/assets/img/FMGTransitionAnimation.svg
Normal file
1
src/assets/img/FMGTransitionAnimation.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 30 KiB |
|
|
@ -5,8 +5,8 @@
|
||||||
<span class="fs-5 fw-bold w-100">{{ questionText }}</span>
|
<span class="fs-5 fw-bold w-100">{{ questionText }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-100 d-flex justify-content-center">
|
<div class="w-100 d-flex justify-content-center">
|
||||||
<fieldset class="w-100" :aria-required=isRequired :class="getFieldSetClasses" :role="isMultiSelect ? 'group' : 'radiogroup'" :aria-labelledby="groupName ? groupName + '-radio-group' : ''">
|
<fieldset class="w-100" :aria-required=isRequired :class="getFieldSetClasses" :role="isMultiSelect ? 'group' : 'radiogroup'" :aria-labelledby="groupName">
|
||||||
<legend class="sr-only" :data-focus-target="groupName" tabindex="-1">
|
<legend class="sr-only" :data-focus-target="groupName" :id="groupName" tabindex="-1">
|
||||||
{{(isMultiSelect && answers && answers.length > 1) ? 'Select one or more options below.' : 'Select an option below.' }}
|
{{(isMultiSelect && answers && answers.length > 1) ? 'Select one or more options below.' : 'Select an option below.' }}
|
||||||
</legend>
|
</legend>
|
||||||
<div :class="getComponentWrapperClasses">
|
<div :class="getComponentWrapperClasses">
|
||||||
|
|
@ -40,8 +40,8 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="row form-test-error">
|
<div class="row form-test-error mt-1">
|
||||||
<error-message class="mt-2" :name="groupName" v-if="!suppressError"></error-message>
|
<error-message :name="groupName" v-if="!suppressError"></error-message>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -52,7 +52,6 @@ import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-bu
|
||||||
import listCard from "@/ux-components/list-card/list-card";
|
import listCard from "@/ux-components/list-card/list-card";
|
||||||
import { ErrorMessage } from 'vee-validate';
|
import { ErrorMessage } from 'vee-validate';
|
||||||
import radio from "@/ux-components/radio/radio";
|
import radio from "@/ux-components/radio/radio";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "buttonQuestion",
|
name: "buttonQuestion",
|
||||||
|
|
@ -135,8 +134,6 @@ export default {
|
||||||
},
|
},
|
||||||
handleCheckedChanged(val) {
|
handleCheckedChanged(val) {
|
||||||
|
|
||||||
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, val.value, true);
|
|
||||||
|
|
||||||
if(this.isMultiSelect && this.selectedValues) {
|
if(this.isMultiSelect && this.selectedValues) {
|
||||||
// Add or remove item to array of data to emit
|
// Add or remove item to array of data to emit
|
||||||
const newSelectedValues = this.selectedValues;
|
const newSelectedValues = this.selectedValues;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="dropdown-question">
|
<div class="dropdown-question" :class="(errors && errors.length) || hasError ? 'has-error' : ''">
|
||||||
<label :for="inputId" :aria-label="questionText" class="form-label" v-html="labelText"></label>
|
<label :for="inputId" :aria-label="questionText" class="form-label" v-html="labelText"></label>
|
||||||
<select v-model="selectedOption"
|
<select v-model="selectedOption"
|
||||||
class="form-select"
|
class="form-select"
|
||||||
|
|
@ -9,8 +9,7 @@
|
||||||
:disabled="isDisabled"
|
:disabled="isDisabled"
|
||||||
:aria-required="isRequired"
|
:aria-required="isRequired"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
@input="handleChange"
|
>
|
||||||
@blur="handleBlur" >
|
|
||||||
<option v-for="(value, name, index) in options" :value="name" :key="index">
|
<option v-for="(value, name, index) in options" :value="name" :key="index">
|
||||||
{{ value }}
|
{{ value }}
|
||||||
</option>
|
</option>
|
||||||
|
|
@ -40,10 +39,23 @@ export default {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
const propsClone = Object.assign({}, props);
|
||||||
|
const modelValue = propsClone.modelValue;
|
||||||
|
let initialValue;
|
||||||
|
|
||||||
|
switch (typeof modelValue) {
|
||||||
|
case "number":
|
||||||
|
initialValue = modelValue;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
initialValue = (modelValue && modelValue.length > 0) ? modelValue : "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const fieldOptions = {
|
const fieldOptions = {
|
||||||
type: "text",
|
type: "select",
|
||||||
value: props.modelValue,
|
value: props.modelValue,
|
||||||
initialValue: props.modelValue,
|
initialValue: initialValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ describe("funnel-footer.vue", () => {
|
||||||
|
|
||||||
const mockMixin = {
|
const mockMixin = {
|
||||||
methods: {
|
methods: {
|
||||||
getCmsContent: jest.fn()
|
getCmsContent: jest.fn(),
|
||||||
|
getFooterInfoBoxHeight: jest.fn(()=>80)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +63,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.paddingHeight = document.querySelector(".footer #infoBox").offsetHeight + 24;
|
this.paddingHeight = this.getFooterInfoBoxHeight() + 24;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
window.addEventListener('resize', this.onResize);
|
window.addEventListener('resize', this.onResize);
|
||||||
})
|
})
|
||||||
|
|
@ -84,7 +84,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onResize() {
|
onResize() {
|
||||||
this.paddingHeight = document.querySelector(".footer #infoBox").offsetHeight;
|
this.paddingHeight = this.getFooterInfoBoxHeight();
|
||||||
},
|
},
|
||||||
updateButtonText(newText) {
|
updateButtonText(newText) {
|
||||||
this.customButtontext = newText;
|
this.customButtontext = newText;
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-show="isModalVisible" class="loading-modal-backdrop">
|
<div v-if="isModalVisible" class="container-fluid modal-loader">
|
||||||
<div class="loading-modal">
|
<div class="row g-2 h-100 d-flex align-items-center">
|
||||||
<section class="loading-modal-body">
|
<div class="container-fluid overflow-hidden">
|
||||||
<div class="modal-icon-container text-center">
|
<div class="row h-100">
|
||||||
<img class="loader-gif" alt="Loading" src="@/assets/img/loader.gif">
|
<div class="col text-center tagbg mb-2">
|
||||||
<img class="modal-icon" alt="" src="@/assets/img/windshield.png">
|
<div class="spinner-border text-danger" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<p class="mb-0 text-center">We're processing your information.</p>
|
||||||
|
<p class="mb-0 text-center">This could take up to 30 seconds...</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center fw-bold fs-5 loading-modal-text">
|
|
||||||
Please wait...
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center fs-5 loading-modal-text">
|
|
||||||
This process can take up to 20 seconds.
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Modal',
|
name: 'Modal',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -27,71 +30,55 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showModal() {
|
showModal() {
|
||||||
|
//Display modal
|
||||||
this.isModalVisible = true;
|
this.isModalVisible = true;
|
||||||
|
//Force page reload on back button
|
||||||
|
window.addEventListener("pageshow", function(evt) {
|
||||||
|
if(evt.persisted){
|
||||||
|
setTimeout(function(){
|
||||||
|
window.location.reload();
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.loading-modal-backdrop {
|
.modal-loader {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
background-color: #e5e5e5;
|
bottom: 0;
|
||||||
|
z-index: 1055;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
outline: 0;
|
||||||
|
background: $gray-100;
|
||||||
|
p {
|
||||||
|
font-family: Roboto;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagbg {
|
||||||
|
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg fill='none' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 84 32'%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' fill='%23fff'/%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' fill='%23fff'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06.8c8.08 0 11.89.935 11.89.935 3.58.576 5.696 7.207 5.696 7.207h.727c0-2.427 1.302-2.397 2.341-2 .723.292 1.363.76 1.86 1.361 1.319 1.547.465 1.674.465 1.674h-5.067l3.846 3.01v12.016c0 2.41-2.029 2.31-2.029 2.31H22.338s-2.029.1-2.029-2.31V12.996l3.84-3.009H19.07s-.853-.127.466-1.674a4.693 4.693 0 0 1 1.86-1.361c1.032-.397 2.341-.427 2.341 2h.736s2.117-6.64 5.696-7.21c0 0 3.81-.942 11.89-.942Z' fill='%23fff' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06 8.847c7.924 0 14.685.511 14.685.511 0-2.585-2.38-6.011-2.38-6.011S50.4 2.519 42.06 2.519s-12.303.828-12.303.828-2.38 3.426-2.38 6.011c0 0 6.76-.51 14.683-.51Z' fill='%23DA291C' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M35.277 16.523a62.558 62.558 0 0 1 13.277 0m3.276-.439s2.384-2.257 8.608-2.257c0 0 1.179 2.657-2.54 3.37m-25.894-1.113s-2.387-2.257-8.611-2.257c0 0-1.16 2.579 2.543 3.37m-3.546 5.856s21.52 3.647 39.123 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
background-size: 96px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 1050;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-modal {
|
.spinner-border {
|
||||||
position: absolute;
|
width: 6.5rem;
|
||||||
background: #ffffff;
|
height: 6.5rem;
|
||||||
padding: 0 0 32px 0;
|
border: 0.45em solid currentColor;
|
||||||
box-shadow: 2px 2px 20px 1px;
|
border-right-color: transparent;
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
border-radius: 4px;
|
|
||||||
top: 48px;
|
|
||||||
height: 246px;
|
|
||||||
width: 327px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-modal-body {
|
|
||||||
position: relative;
|
|
||||||
padding: 20px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-modal-text {
|
|
||||||
padding: 0 24px 0 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-icon-container {
|
|
||||||
position: relative;
|
|
||||||
width: 75px;
|
|
||||||
height: 75px;
|
|
||||||
margin: 15px auto;
|
|
||||||
padding-bottom: 26px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-icon-container img {
|
|
||||||
position: absolute;
|
|
||||||
vertical-align: middle;
|
|
||||||
border: 0;
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader-gif {
|
|
||||||
width: 75px;
|
|
||||||
height: 75px;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<label :for="inputId" :aria-label="questionText" class="form-label" v-html="labelText"></label>
|
<label :for="inputId" :aria-label="questionText" class="form-label" v-html="labelText"></label>
|
||||||
<!-- See https://stackoverflow.com/a/30976223 for information about "do-not-autofill" -->
|
<!-- See https://stackoverflow.com/a/30976223 for information about "do-not-autofill" -->
|
||||||
<input
|
<input
|
||||||
v-model="value"
|
v-model.trim="value"
|
||||||
v-maska="mask"
|
v-maska="mask"
|
||||||
:type="type"
|
:type="type"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
|
|
@ -17,27 +17,29 @@
|
||||||
autocomplete="do-not-autofill"
|
autocomplete="do-not-autofill"
|
||||||
:class="[hasIcon ? 'has-icon' : '', iconRight ? 'icon-right' : '']"
|
:class="[hasIcon ? 'has-icon' : '', iconRight ? 'icon-right' : '']"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
|
@change="handleChange"
|
||||||
|
@blur="handleChange"
|
||||||
|
:maxlength="maxLength ? maxLength : '999'"
|
||||||
/>
|
/>
|
||||||
<div v-show="errorMessage" class="row mt-2 form-test-error">
|
<div v-show="errorMessage" class="row my-2 form-test-error">
|
||||||
<span role="alert">{{ errorMessage }}</span>
|
<span class="d-inline-flex mt-0" role="alert">{{ errorMessage }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useField, validate } from "vee-validate";
|
||||||
import { useField } from "vee-validate";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "textbox-question",
|
name: "textbox-question",
|
||||||
props: {
|
props: {
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'text',
|
default: "text",
|
||||||
},
|
},
|
||||||
placeholderText: {
|
placeholderText: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: "",
|
||||||
},
|
},
|
||||||
modelValue: String,
|
modelValue: String,
|
||||||
inputId: String,
|
inputId: String,
|
||||||
|
|
@ -49,10 +51,12 @@ export default {
|
||||||
hasError: Boolean,
|
hasError: Boolean,
|
||||||
mask: {
|
mask: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: "",
|
||||||
},
|
},
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
cmsWidgetName: String
|
semiAggressiveValidation: Boolean,
|
||||||
|
cmsWidgetName: String,
|
||||||
|
maxLength: String,
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const propsClone = Object.assign({}, props);
|
const propsClone = Object.assign({}, props);
|
||||||
|
|
@ -71,17 +75,11 @@ export default {
|
||||||
const fieldOptions = {
|
const fieldOptions = {
|
||||||
type: "text",
|
type: "text",
|
||||||
value: modelValue,
|
value: modelValue,
|
||||||
initialValue: initialValue
|
initialValue: initialValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const { errorMessage, handleBlur, handleChange, meta, validate, errors } =
|
||||||
errorMessage,
|
useField(props.inputId, props.validationRules, fieldOptions);
|
||||||
handleBlur,
|
|
||||||
handleChange,
|
|
||||||
meta,
|
|
||||||
validate,
|
|
||||||
errors,
|
|
||||||
} = useField(props.inputId, props.validationRules, fieldOptions);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
|
@ -93,16 +91,16 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
questionText(){
|
questionText() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
get: function() {
|
get: function () {
|
||||||
return this.modelValue;
|
return this.modelValue;
|
||||||
},
|
},
|
||||||
set: function(newValue) {
|
set: function (newValue) {
|
||||||
this.$emit("update:modelValue", newValue);
|
this.$emit("update:modelValue", newValue);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
labelText: {
|
labelText: {
|
||||||
get: function () {
|
get: function () {
|
||||||
|
|
@ -112,7 +110,11 @@ export default {
|
||||||
var words = this.questionText.toString().split(/[ ]+/);
|
var words = this.questionText.toString().split(/[ ]+/);
|
||||||
words.forEach(function (word) {
|
words.forEach(function (word) {
|
||||||
const position = 1;
|
const position = 1;
|
||||||
word = [word.toString().slice(0, position), noBreakChar, word.toString().slice(position)].join('');
|
word = [
|
||||||
|
word.toString().slice(0, position),
|
||||||
|
noBreakChar,
|
||||||
|
word.toString().slice(position),
|
||||||
|
].join("");
|
||||||
questionText += `${word} `;
|
questionText += `${word} `;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -122,14 +124,19 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return questionText;
|
return questionText;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
async value(newValue) {
|
||||||
|
if (this.semiAggressiveValidation) {
|
||||||
|
const result = await validate(newValue, this.validationRules); // do a test validation check, without triggering full validation
|
||||||
|
if (result.valid) {
|
||||||
|
this.handleChange(newValue); // trigger full validation on this field only
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
},
|
||||||
value(newValue) {
|
|
||||||
this.handleChange(newValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -159,6 +166,7 @@ export default {
|
||||||
border: 1px solid $gray-500;
|
border: 1px solid $gray-500;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
min-height: 3rem;
|
min-height: 3rem;
|
||||||
|
padding: 12px 16px;
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: $gray-500;
|
color: $gray-500;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ const GaLabels = {
|
||||||
ERROR: 'Error',
|
ERROR: 'Error',
|
||||||
LICENSE_PLATE_LOOKUP: 'License_Plate_Look_Up',
|
LICENSE_PLATE_LOOKUP: 'License_Plate_Look_Up',
|
||||||
VIN_LOOKUP: 'Vin_Look_Up',
|
VIN_LOOKUP: 'Vin_Look_Up',
|
||||||
|
ADDRESS_LOOKUP: 'Address_Look_up',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ const errorMessages = {
|
||||||
LAST_NAME_REQUIRED: "Please enter your last name",
|
LAST_NAME_REQUIRED: "Please enter your last name",
|
||||||
EMAIL_ADDRESS_REQUIRED: "Please enter your email address",
|
EMAIL_ADDRESS_REQUIRED: "Please enter your email address",
|
||||||
EMAIL_ADDRESS_FORMAT: "Please enter a valid email address",
|
EMAIL_ADDRESS_FORMAT: "Please enter a valid email address",
|
||||||
SERVICE_ZIP_REQUIRED: "Please enter your Service ZIP",
|
SERVICE_ZIP_REQUIRED: "Please enter your service ZIP",
|
||||||
SERVICE_ZIP_FORMAT: "Please enter a valid Service ZIP",
|
SERVICE_ZIP_FORMAT: "Please enter a valid service ZIP",
|
||||||
VIN_REQUIRED: "Please enter your VIN",
|
VIN_REQUIRED: "Please enter your VIN",
|
||||||
VIN_FORMAT: "Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q",
|
VIN_FORMAT: "Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q",
|
||||||
OPTION_REQUIRED: "Please select an option",
|
OPTION_REQUIRED: "Please select an option",
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ const storeMutations = {
|
||||||
UPDATE_REGISTRATION_FIRST_NAME: "updateRegistrationFirstName",
|
UPDATE_REGISTRATION_FIRST_NAME: "updateRegistrationFirstName",
|
||||||
UPDATE_REGISTRATION_LAST_NAME: "updateRegistrationLastName",
|
UPDATE_REGISTRATION_LAST_NAME: "updateRegistrationLastName",
|
||||||
UPDATE_SERVICE_LOCATION_ZIP_CODE: "updateServiceLocationZipCode",
|
UPDATE_SERVICE_LOCATION_ZIP_CODE: "updateServiceLocationZipCode",
|
||||||
|
UPDATE_SERVICE_LOCATION_STATE: "updateServiceLocationState",
|
||||||
UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress",
|
UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress",
|
||||||
|
|
||||||
// ORDER MUTATIONS
|
// ORDER MUTATIONS
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,19 @@ import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
|
||||||
export function getDamageString() {
|
export function getDamageString() {
|
||||||
|
// If it's a repair it's always a windshield.
|
||||||
|
const isRepair = store.getters.damage.isRepair;
|
||||||
|
if(isRepair){
|
||||||
|
return "windshield"
|
||||||
|
}
|
||||||
|
|
||||||
const damageLocations = store.getters.damage.glassToReplace;
|
const damageLocations = store.getters.damage.glassToReplace;
|
||||||
|
|
||||||
let returnString;
|
let returnString;
|
||||||
if (!damageLocations) {
|
if (!damageLocations) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (damageLocations.length > 1) {
|
if (damageLocations.length > 1) {
|
||||||
returnString = "match"
|
returnString = "match"
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import { applicationConfig } from "@/constants/application-config";
|
||||||
Will update the cookie if present, or create a new one if not.
|
Will update the cookie if present, or create a new one if not.
|
||||||
*/
|
*/
|
||||||
export function updateOrCreateFunnelCookie() {
|
export function updateOrCreateFunnelCookie() {
|
||||||
|
const wasClaimRegistrationDelayed = getFunnelCookie()?.HasDelayedClaimRegistration;
|
||||||
|
|
||||||
// Create the cookie
|
// Create the cookie
|
||||||
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}={}; path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()};`;
|
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}={}; path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()};`;
|
||||||
|
|
||||||
|
|
@ -19,6 +21,7 @@ export function updateOrCreateFunnelCookie() {
|
||||||
ReferralDate: store.getters.order.referralDate,
|
ReferralDate: store.getters.order.referralDate,
|
||||||
ReferralCorrelationId: store.getters.order.referralCorrelationId,
|
ReferralCorrelationId: store.getters.order.referralCorrelationId,
|
||||||
ReferralParentAccountNumber: store.getters.order.accountNumber,
|
ReferralParentAccountNumber: store.getters.order.accountNumber,
|
||||||
|
HasDelayedClaimRegistration: wasClaimRegistrationDelayed
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -305,7 +305,7 @@ describe("getPageToRouteExistingOrderTo", () => {
|
||||||
describe("navigateToHeritageFunnel", () => {
|
describe("navigateToHeritageFunnel", () => {
|
||||||
test("should save order", async () => {
|
test("should save order", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mockReferralNumber = 2;
|
const mockReferralNumber = "2";
|
||||||
const mockCorrelationId = "55";
|
const mockCorrelationId = "55";
|
||||||
const mockReferralDate = "2022";
|
const mockReferralDate = "2022";
|
||||||
|
|
||||||
|
|
@ -337,7 +337,7 @@ describe("navigateToHeritageFunnel", () => {
|
||||||
|
|
||||||
test("should go to heritage funnel", async () => {
|
test("should go to heritage funnel", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mockReferralNumber = 2;
|
const mockReferralNumber = "2";
|
||||||
const mockCorrelationId = "55";
|
const mockCorrelationId = "55";
|
||||||
const mockReferralDate = "2022";
|
const mockReferralDate = "2022";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,10 @@ export async function saveOrder() {
|
||||||
|
|
||||||
// Save the referral information back from the store.
|
// Save the referral information back from the store.
|
||||||
await baseMixin.methods.dispatchStoreAction(storeActions.SET_REFERRAL_INFORMATION, {
|
await baseMixin.methods.dispatchStoreAction(storeActions.SET_REFERRAL_INFORMATION, {
|
||||||
referralNumber: savedOrderInfo.data.referralNumber,
|
referralNumber: savedOrderInfo.data.referralNumber.toString(),
|
||||||
referralCorrelationId: savedOrderInfo.data.referralCorrelationId,
|
referralCorrelationId: savedOrderInfo.data.referralCorrelationId,
|
||||||
referralDate: savedOrderInfo.data.referralDate,
|
referralDate: savedOrderInfo.data.referralDate,
|
||||||
accountNumber: savedOrderInfo.data.accountNumber
|
accountNumber: savedOrderInfo.data.accountNumber.toString()
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
// Update the cookie with the referral information when saved.
|
// Update the cookie with the referral information when saved.
|
||||||
|
|
|
||||||
|
|
@ -103,11 +103,12 @@ describe("saveOrder", () => {
|
||||||
|
|
||||||
test("saveOrder => should set state order values", async () => {
|
test("saveOrder => should set state order values", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const mockReferralNumber = 2;
|
const mockReferralNumber = "2";
|
||||||
const mockCorrelationId = "55";
|
const mockCorrelationId = "55";
|
||||||
const mockReferralDate = "2022";
|
const mockReferralDate = "2022";
|
||||||
|
const mockAccountNumber = "5";
|
||||||
|
|
||||||
const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate);
|
const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber);
|
||||||
|
|
||||||
const mockData = {
|
const mockData = {
|
||||||
actionList: [
|
actionList: [
|
||||||
|
|
@ -131,7 +132,8 @@ describe("saveOrder", () => {
|
||||||
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.SET_REFERRAL_INFORMATION, {
|
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.SET_REFERRAL_INFORMATION, {
|
||||||
referralNumber: mockReferralNumber,
|
referralNumber: mockReferralNumber,
|
||||||
referralDate: mockReferralDate,
|
referralDate: mockReferralDate,
|
||||||
referralCorrelationId: mockCorrelationId
|
referralCorrelationId: mockCorrelationId,
|
||||||
|
accountNumber: mockAccountNumber
|
||||||
}, false);
|
}, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,12 @@ export function removeAllTestCookies() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate) {
|
export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, accountNumber = "0") {
|
||||||
return {
|
return {
|
||||||
referralNumber: mockReferralNumber,
|
referralNumber: mockReferralNumber,
|
||||||
referralCorrelationId: mockCorrelationId,
|
referralCorrelationId: mockCorrelationId,
|
||||||
referralDate: mockReferralDate
|
referralDate: mockReferralDate,
|
||||||
|
accountNumber: accountNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,28 +12,28 @@
|
||||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" />
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" />
|
||||||
<div class="fade-on-route-transition sub-container make-tall">
|
<div class="fade-on-route-transition sub-container make-tall">
|
||||||
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
|
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
|
||||||
<alert ref="alertVinNotFound" v-show="displayVinNotFoundAlert"
|
<alert ref="alertVinNotFound" v-if="displayVinNotFoundAlert"
|
||||||
class="my-3"
|
class="mb-4"
|
||||||
cmsWidgetName="AlertVinNotFoundWidget"
|
cmsWidgetName="AlertVinNotFoundWidget"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
<alert ref="alertMatchedDifferentVehicle" v-show="displayMatchedDifferentVehicleAlert"
|
<alert ref="alertMatchedDifferentVehicle" v-if="displayMatchedDifferentVehicleAlert"
|
||||||
class="my-3"
|
class="mb-4"
|
||||||
:manualHeadline="AlertMatchedDifferentVehicleHeader"
|
:manualHeadline="AlertMatchedDifferentVehicleHeader"
|
||||||
:manualCopy="AlertMatchedDifferentVehicleBody"
|
:manualCopy="AlertMatchedDifferentVehicleBody"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
<alert ref="alertNonServiceableZip" v-show="displayNonServiceableZipAlert"
|
<alert ref="alertNonServiceableZip" v-if="displayNonServiceableZipAlert"
|
||||||
class="my-3"
|
class="mb-4"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
:manualHeadline="AlertNonServiceableZipHeader"
|
:manualHeadline="AlertNonServiceableZipHeader"
|
||||||
:manualCopy="AlertNonServiceableZipBody"
|
:manualCopy="AlertNonServiceableZipBody"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
<alert ref="alertVinLookupsByHomeAddressNotAllowed" v-show="displayVinLookupByHomeAddressNotAllowedAlert"
|
<alert ref="alertVinLookupsByHomeAddressNotAllowed" v-if="displayVinLookupByHomeAddressNotAllowedAlert"
|
||||||
class="my-3"
|
class="mb-4"
|
||||||
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
|
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
|
|
@ -72,10 +72,8 @@ import alert from "@/ux-components/alert/alert";
|
||||||
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
|
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
|
||||||
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
||||||
|
|
||||||
import { Form } from "vee-validate";
|
import { Form, defineRule } from "vee-validate";
|
||||||
import { defineRule } from "vee-validate";
|
import { required, regex } from "@/helpers/validation-rules";
|
||||||
import { required } from "@/helpers/validation-rules";
|
|
||||||
import { regex } from "@/helpers/validation-rules";
|
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
|
||||||
// Supporting files
|
// Supporting files
|
||||||
|
|
@ -151,6 +149,16 @@ export default {
|
||||||
this.navigationScenarios.CLICKED_BACK,
|
this.navigationScenarios.CLICKED_BACK,
|
||||||
this.$route
|
this.$route
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
attachCustomEvents() {
|
||||||
|
this.prependActionToMethod(this, this.forwardButtonAction, () => {
|
||||||
|
this.pushEventToGA(
|
||||||
|
this.$route.query[this.queryStrings.FMG_PAGE],
|
||||||
|
this.GaActions.SUBMITTED,
|
||||||
|
this.GaLabels.ADDRESS_LOOKUP,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
getRegistrationAddressFromStore() {
|
getRegistrationAddressFromStore() {
|
||||||
return store.getters.vehicle.registration.address;
|
return store.getters.vehicle.registration.address;
|
||||||
|
|
@ -180,7 +188,7 @@ export default {
|
||||||
this.resetWarningsAndErrors();
|
this.resetWarningsAndErrors();
|
||||||
|
|
||||||
// Lookup VIN(s) with the provided address
|
// Lookup VIN(s) with the provided address
|
||||||
const vinLookup = this.lookupVin(
|
const vinLookupPromise = this.lookupVin(
|
||||||
this.customerQuestions.lastName,
|
this.customerQuestions.lastName,
|
||||||
this.customerQuestions.addressQuestions.streetAddress,
|
this.customerQuestions.addressQuestions.streetAddress,
|
||||||
this.customerQuestions.addressQuestions.zipCode,
|
this.customerQuestions.addressQuestions.zipCode,
|
||||||
|
|
@ -188,10 +196,10 @@ export default {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify if the service zip code or registration zip code provided is serviceable
|
// Verify if the service zip code or registration zip code provided is serviceable
|
||||||
const zipValidation = this.serviceZipCode ? this.validateZip(this.serviceZipCode) : this.validateZip(this.customerQuestions.addressQuestions.zipCode);
|
const serviceZipValidationPromise = this.serviceZipCode ? this.validateZip(this.serviceZipCode) : this.validateZip(this.customerQuestions.addressQuestions.zipCode);
|
||||||
|
|
||||||
const vinLookupResponse = await vinLookup;
|
const vinLookupResponse = await vinLookupPromise;
|
||||||
const zipValidationResponse = await zipValidation;
|
const serviceZipValidationResponse = await serviceZipValidationPromise;
|
||||||
|
|
||||||
if (!vinLookupResponse.data.isStatePermissible) {
|
if (!vinLookupResponse.data.isStatePermissible) {
|
||||||
// State Restrictions forbid lookup by address
|
// State Restrictions forbid lookup by address
|
||||||
|
|
@ -201,7 +209,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the neither the registration zip code or service zip code are not serviceable
|
// if the neither the registration zip code or service zip code are not serviceable
|
||||||
this.isZipServicable = zipValidationResponse.data.isServiceable;
|
this.isZipServicable = serviceZipValidationResponse.data.isServiceable;
|
||||||
if (!this.isZipServicable) {
|
if (!this.isZipServicable) {
|
||||||
this.displayNonServiceableZipAlert = true;
|
this.displayNonServiceableZipAlert = true;
|
||||||
this.showServiceZipField = true;
|
this.showServiceZipField = true;
|
||||||
|
|
@ -245,15 +253,24 @@ export default {
|
||||||
|
|
||||||
// update data if the zip or service zip is servicable
|
// update data if the zip or service zip is servicable
|
||||||
this.updateVehicleInfo(carsFound[0].vin, carFound);
|
this.updateVehicleInfo(carsFound[0].vin, carFound);
|
||||||
this.updateCustomerInfo();
|
this.updateCustomerInfo(serviceZipValidationResponse.data.state);
|
||||||
|
|
||||||
} else if (carsFound.length > 1) {
|
} else if (carsFound.length > 1) {
|
||||||
if (!this.isZipServicable) {
|
if (!this.isZipServicable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if multiple cars were found
|
||||||
|
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
|
||||||
|
if (matchingCars.length === 1) {
|
||||||
|
// and one and only one of them matches the carId entered, save the vehicle info
|
||||||
|
// so we can go to the Heritage Funnel directly
|
||||||
|
const matchingCar = matchingCars[0];
|
||||||
|
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
// update data if the zip or service zip is servicable
|
// update data if the zip or service zip is servicable
|
||||||
this.updateCustomerInfo();
|
this.updateCustomerInfo(serviceZipValidationResponse.data.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.navigateForward(carEntered, carsFound);
|
this.navigateForward(carEntered, carsFound);
|
||||||
|
|
@ -286,12 +303,16 @@ export default {
|
||||||
}
|
}
|
||||||
} else if (carsFound.length > 1) {
|
} else if (carsFound.length > 1) {
|
||||||
// if multiple cars were found
|
// if multiple cars were found
|
||||||
if (carsFound.find(car => car.vehicle.carId === carEntered.carId)) {
|
let matchingCars = carsFound.filter(car => car.vehicle.carId === carEntered.carId);
|
||||||
// and one of them matches the car id entered
|
if (matchingCars.length === 1) {
|
||||||
this.$refs.loadingModal.showModal();
|
this.$refs.loadingModal.showModal();
|
||||||
|
|
||||||
|
// and one and only of them matches the car id entered
|
||||||
|
const matchingCar = matchingCars[0];
|
||||||
|
this.updateVehicleInfo(matchingCar.vin, matchingCar.vehicle);
|
||||||
navigateAfterSaveToHeritageFunnel(this.$route);
|
navigateAfterSaveToHeritageFunnel(this.$route);
|
||||||
} else {
|
} else {
|
||||||
// and there is no match, navigate to "address-vehicles" page
|
// if there are no matches or there are multiple matches, navigate to "address-vehicles" page
|
||||||
this.$router.navigateAfterSave(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound);
|
this.$router.navigateAfterSave(this.navigationScenarios.CONTINUING_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, carsFound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -325,7 +346,7 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, vehicleInfo.imageVifNumber);
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, vehicleInfo.imageVifNumber);
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, vehicleInfo.imageColor);
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, vehicleInfo.imageColor);
|
||||||
},
|
},
|
||||||
updateCustomerInfo() {
|
updateCustomerInfo(serviceState) {
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_ADDRESS, this.customerQuestions.addressQuestions.streetAddress);
|
store.commit(storeMutations.UPDATE_REGISTRATION_ADDRESS, this.customerQuestions.addressQuestions.streetAddress);
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_CITY, this.customerQuestions.addressQuestions.city);
|
store.commit(storeMutations.UPDATE_REGISTRATION_CITY, this.customerQuestions.addressQuestions.city);
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_STATE, this.customerQuestions.addressQuestions.state);
|
store.commit(storeMutations.UPDATE_REGISTRATION_STATE, this.customerQuestions.addressQuestions.state);
|
||||||
|
|
@ -333,9 +354,9 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_FIRST_NAME, this.customerQuestions.firstName);
|
store.commit(storeMutations.UPDATE_REGISTRATION_FIRST_NAME, this.customerQuestions.firstName);
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_LAST_NAME, this.customerQuestions.lastName);
|
store.commit(storeMutations.UPDATE_REGISTRATION_LAST_NAME, this.customerQuestions.lastName);
|
||||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.serviceZipCode);
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.serviceZipCode);
|
||||||
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, serviceState);
|
||||||
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.customerQuestions.emailAddress);
|
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.customerQuestions.emailAddress);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateServiceLocationIfNecessary() {
|
updateServiceLocationIfNecessary() {
|
||||||
const serviceLocation = store.getters.order.serviceLocation;
|
const serviceLocation = store.getters.order.serviceLocation;
|
||||||
|
|
||||||
|
|
@ -345,6 +366,9 @@ export default {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.attachCustomEvents();
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
AlertNonServiceableZipHeader(){
|
AlertNonServiceableZipHeader(){
|
||||||
|
|
@ -360,13 +384,14 @@ export default {
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
AlertMatchedDifferentVehicleBody(){
|
AlertMatchedDifferentVehicleBody(){
|
||||||
let content = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText");
|
|
||||||
content = content.replaceAll("{custom:glassText}", getDamageString());
|
|
||||||
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
|
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
|
||||||
const vinYmmExpected = `${store.getters.vehicle.year} ${store.getters.vehicle.make} ${store.getters.vehicle.model}`;
|
const vinYmmExpected = `${store.getters.vehicle.year} ${store.getters.vehicle.make} ${store.getters.vehicle.model}`;
|
||||||
|
|
||||||
content = content.replaceAll("{custom:vinYmmFound}", vinYmmFound);
|
const content = this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
|
||||||
content = content.replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
|
.replaceAll("{custom:glassText}", getDamageString())
|
||||||
|
.replaceAll("{custom:vinYmmFound}", vinYmmFound)
|
||||||
|
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,70 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="row mt-2 mb-4">
|
<div class="row mt-2 mb-4">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="StreetAddressQuestionWidget" v-model="addressModel.streetAddress" ref="autocomplete" inputId="autocomplete" placeholderText="Search" aria-haspopup="" hasIcon disableAutoFill validationRules="street-address-required" />
|
<textboxQuestion
|
||||||
|
id="streetAddressField"
|
||||||
|
cmsWidgetName="StreetAddressQuestionWidget"
|
||||||
|
v-model="addressModel.streetAddress"
|
||||||
|
ref="autocomplete"
|
||||||
|
inputId="autocomplete"
|
||||||
|
placeholderText="Search"
|
||||||
|
aria-haspopup=""
|
||||||
|
hasIcon
|
||||||
|
disableAutoFill
|
||||||
|
validationRules="street-address-required"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<div class="row mb-4" v-show="showAddressFields" aria-live="polite">
|
<div class="row mb-4" v-show="showAddressFields" aria-live="polite">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="CityQuestionWidget" v-model="addressModel.city" ref="city" inputId="cbf28188fdf2436688fd735915f7ee56" disableAutoFill validationRules="city-required"/>
|
<textboxQuestion
|
||||||
|
cmsWidgetName="CityQuestionWidget"
|
||||||
|
v-model="addressModel.city"
|
||||||
|
ref="city"
|
||||||
|
inputId="cbf28188fdf2436688fd735915f7ee56"
|
||||||
|
disableAutoFill
|
||||||
|
validationRules="city-required"
|
||||||
|
semiAggressiveValidation
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<div class="row mb-4" v-show="showAddressFields" aria-live="polite">
|
<div class="row mb-4" v-show="showAddressFields" aria-live="polite">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<dropdownQuestion cmsWidgetName="StateQuestionWidget" v-model="addressModel.state" ref="state" inputId="8fdf9dc2e13e430eb57529499dceb3eb" :options="stateOptions" disableAutoFill validationRules="state-required" />
|
<dropdownQuestion
|
||||||
|
cmsWidgetName="StateQuestionWidget"
|
||||||
|
v-model="addressModel.state"
|
||||||
|
ref="state"
|
||||||
|
inputId="8fdf9dc2e13e430eb57529499dceb3eb"
|
||||||
|
:options="stateOptions"
|
||||||
|
disableAutoFill
|
||||||
|
validationRules="state-required"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="ZipQuestionWidget" v-model="addressModel.zipCode" ref="zipCode" inputId="01a9a1c2de0b4c9da8e023c9ae3be498" mask="#####" disableAutoFill validationRules="zip-code-required|zip-code-format"/>
|
<textboxQuestion
|
||||||
|
cmsWidgetName="ZipQuestionWidget"
|
||||||
|
v-model="addressModel.zipCode"
|
||||||
|
ref="zipCode"
|
||||||
|
inputId="01a9a1c2de0b4c9da8e023c9ae3be498"
|
||||||
|
mask="#####"
|
||||||
|
disableAutoFill
|
||||||
|
validationRules="zip-code-required|zip-code-format"
|
||||||
|
semiAggressiveValidation
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<alert ref="alertVerificationWarning" v-show="displayVerificationWarning"
|
<alert ref="alertVerificationWarning" v-if="displayVerificationWarning"
|
||||||
|
class="mb-4"
|
||||||
cmsWidgetName="AlertVerificationWarningWidget"
|
cmsWidgetName="AlertVerificationWarningWidget"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
<alert ref="alertNoMatchWarning" v-show="displayNoMatchWarning"
|
<alert ref="alertNoMatchWarning" v-if="displayNoMatchWarning"
|
||||||
|
class="mb-4"
|
||||||
cmsWidgetName="AlertNoMatchWarningWidget"
|
cmsWidgetName="AlertNoMatchWarningWidget"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
|
|
@ -34,18 +72,19 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
|
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
|
||||||
import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question";
|
import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question";
|
||||||
import alert from "@/ux-components/alert/alert";
|
import alert from "@/ux-components/alert/alert";
|
||||||
import { applicationConfig } from "@/constants/application-config.js";
|
import { applicationConfig } from "@/constants/application-config.js";
|
||||||
import { defineRule } from "vee-validate";
|
import { defineRule } from "vee-validate";
|
||||||
import { required } from "@/helpers/validation-rules";
|
import { required, regex } from "@/helpers/validation-rules";
|
||||||
import { regex } from "@/helpers/validation-rules";
|
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("street-address-required", required(errorMessages.STREET_ADDRESS_REQUIRED));
|
defineRule(
|
||||||
|
"street-address-required",
|
||||||
|
required(errorMessages.STREET_ADDRESS_REQUIRED)
|
||||||
|
);
|
||||||
defineRule("city-required", required(errorMessages.CITY_REQUIRED));
|
defineRule("city-required", required(errorMessages.CITY_REQUIRED));
|
||||||
defineRule("state-required", required(errorMessages.STATE_REQUIRED));
|
defineRule("state-required", required(errorMessages.STATE_REQUIRED));
|
||||||
defineRule("zip-code-required", required(errorMessages.ZIP_REQUIRED));
|
defineRule("zip-code-required", required(errorMessages.ZIP_REQUIRED));
|
||||||
|
|
@ -153,6 +192,7 @@ export default ({
|
||||||
this.addressModel.zipCode !== null) {
|
this.addressModel.zipCode !== null) {
|
||||||
|
|
||||||
this.showAddressFields = true;
|
this.showAddressFields = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const addressField1 = document.getElementById("autocomplete");
|
const addressField1 = document.getElementById("autocomplete");
|
||||||
|
|
@ -173,7 +213,7 @@ export default ({
|
||||||
);
|
);
|
||||||
|
|
||||||
// Standard place_changed event handling
|
// Standard place_changed event handling
|
||||||
autocomplete.addListener('place_changed', fillInAddress);
|
const autocompleteListener = window.google.maps.event.addListener(autocomplete, 'place_changed', fillInAddress);
|
||||||
|
|
||||||
// Wrapping the addressField1 element in the Google Address Autocomplete object
|
// Wrapping the addressField1 element in the Google Address Autocomplete object
|
||||||
// will cause "autocomplete='off'" which Chrome completely ignores. This event
|
// will cause "autocomplete='off'" which Chrome completely ignores. This event
|
||||||
|
|
@ -181,6 +221,14 @@ export default ({
|
||||||
// https://stackoverflow.com/a/30976223
|
// https://stackoverflow.com/a/30976223
|
||||||
addressField1.addEventListener("focus", () => {
|
addressField1.addEventListener("focus", () => {
|
||||||
addressField1.setAttribute("autocomplete", "do-not-autofill");
|
addressField1.setAttribute("autocomplete", "do-not-autofill");
|
||||||
|
|
||||||
|
// Make place results box stick to the input on scroll
|
||||||
|
const streetAddressField = document.getElementById("streetAddressField");
|
||||||
|
const autocompleteResultsContainer = document.getElementsByClassName("pac-container")[0];
|
||||||
|
if (autocompleteResultsContainer) {
|
||||||
|
streetAddressField.appendChild(autocompleteResultsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
addressField1.onchange = function() {
|
addressField1.onchange = function() {
|
||||||
|
|
@ -230,7 +278,7 @@ export default ({
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "route": {
|
case "route": {
|
||||||
self.addressModel.streetAddress += ' ' + component.short_name;
|
self.addressModel.streetAddress += " " + component.short_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "locality": {
|
case "locality": {
|
||||||
|
|
@ -245,7 +293,6 @@ export default ({
|
||||||
self.addressModel.zipCode = component.long_name;
|
self.addressModel.zipCode = component.long_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,6 +303,14 @@ export default ({
|
||||||
self.displayVerificationWarning = true;
|
self.displayVerificationWarning = true;
|
||||||
self.displayNoMatchWarning = false;
|
self.displayNoMatchWarning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// after showing the address fields, disable the address autocomplete
|
||||||
|
window.google.maps.event.removeListener(autocompleteListener);
|
||||||
|
window.google.maps.event.clearInstanceListeners(autocomplete);
|
||||||
|
addressField1.onchange = null;
|
||||||
|
const pacContainer = document.querySelector(".pac-container");
|
||||||
|
pacContainer.remove();
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|
@ -269,8 +324,17 @@ export default ({
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
addressModel: {
|
addressModel: {
|
||||||
handler(newValue){
|
handler(newValue) {
|
||||||
|
// The first time the address model changes is w
|
||||||
|
if (!newValue.city &&
|
||||||
|
!newValue.state &&
|
||||||
|
!newValue.zipCode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.displayNoMatchWarning === true) {
|
||||||
this.displayNoMatchWarning = false;
|
this.displayNoMatchWarning = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
|
|
@ -282,3 +346,14 @@ export default ({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
#streetAddressField {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.pac-container {
|
||||||
|
top: 76px !important; // Height of #streetAddressField
|
||||||
|
left: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,39 @@
|
||||||
<addressQuestions ref="addressQuestions" v-model="customerModel.addressQuestions" :alertNotifications="alertNotifications" />
|
<addressQuestions ref="addressQuestions" v-model="customerModel.addressQuestions" :alertNotifications="alertNotifications" />
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="FirstNameQuestionWidget" v-model="customerModel.firstName" ref="firstName" inputId="08497a2efd9a4a73a70360ab47b4838d" disableAutoFill validationRules="first-name-required" />
|
<textboxQuestion
|
||||||
|
cmsWidgetName="FirstNameQuestionWidget"
|
||||||
|
v-model="customerModel.firstName"
|
||||||
|
ref="firstName"
|
||||||
|
inputId="08497a2efd9a4a73a70360ab47b4838d"
|
||||||
|
disableAutoFill
|
||||||
|
validationRules="first-name-required"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="LastNameQuestionWidget" v-model="customerModel.lastName" ref="lastName" inputId="0030e56a57e74a4ab92de7fb8e97fec5" disableAutoFill validationRules="last-name-required" />
|
<textboxQuestion
|
||||||
|
cmsWidgetName="LastNameQuestionWidget"
|
||||||
|
v-model="customerModel.lastName"
|
||||||
|
ref="lastName"
|
||||||
|
inputId="0030e56a57e74a4ab92de7fb8e97fec5"
|
||||||
|
disableAutoFill
|
||||||
|
validationRules="last-name-required"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-4">
|
<div class="row mb-5">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="EmailAddressQuestionWidget" v-model="customerModel.emailAddress" ref="emailAddress" inputId="00450a91b8964a768ce3992e6feb890f" disableAutoFill validationRules="email-address-required|email-address-format"/>
|
<textboxQuestion
|
||||||
|
cmsWidgetName="EmailAddressQuestionWidget"
|
||||||
|
v-model="customerModel.emailAddress"
|
||||||
|
ref="emailAddress"
|
||||||
|
inputId="00450a91b8964a768ce3992e6feb890f"
|
||||||
|
disableAutoFill
|
||||||
|
validationRules="email-address-required|email-address-format"
|
||||||
|
semiAggressiveValidation
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -29,7 +51,7 @@ import { errorMessages } from "@/constants/error-messages";
|
||||||
defineRule("first-name-required", required(errorMessages.FIRST_NAME_REQUIRED));
|
defineRule("first-name-required", required(errorMessages.FIRST_NAME_REQUIRED));
|
||||||
defineRule("last-name-required", required(errorMessages.LAST_NAME_REQUIRED));
|
defineRule("last-name-required", required(errorMessages.LAST_NAME_REQUIRED));
|
||||||
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
|
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
|
||||||
defineRule("email-address-format", regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+).([a-zA-Z]{2,})$/, errorMessages.EMAIL_ADDRESS_FORMAT));
|
defineRule("email-address-format", regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, errorMessages.EMAIL_ADDRESS_FORMAT));
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
name: "customer-questions",
|
name: "customer-questions",
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
v-model="selectedVehicleVin"
|
v-model="selectedVehicleVin"
|
||||||
:isCarIdDifferent="isCarIdDifferent"
|
:isCarIdDifferent="isCarIdDifferent"
|
||||||
/>
|
/>
|
||||||
<div class="alert-provide-vin my-5" v-if="splitAlertProvideVinBodyForLink.length">
|
<div class="alert-provide-vin my-3" v-if="splitAlertProvideVinBodyForLink.length">
|
||||||
<span v-for="copy in splitAlertProvideVinBodyForLink" :key="copy">
|
<span v-for="copy in splitAlertProvideVinBodyForLink" :key="copy">
|
||||||
<span v-if="copy.includes('routerLink:')" class="text-body">
|
<span v-if="copy.includes('routerLink:')" class="text-body">
|
||||||
<router-link :to="{query: {fmgPage: `${copy.split(':')[1].split(',')[0]}`}, name: 'root'}">{{ copy.split(':')[1].split(',')[1] }}</router-link>
|
<router-link :to="{query: {fmgPage: `${copy.split(':')[1].split(',')[0]}`}, name: 'root'}">{{ copy.split(':')[1].split(',')[1] }}</router-link>
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,6 @@ describe("license-plate-lookup.vue", () => {
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
|
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,28 +8,73 @@
|
||||||
<div class="fade-on-route-transition sub-container make-tall">
|
<div class="fade-on-route-transition sub-container make-tall">
|
||||||
<div class="row my-2">
|
<div class="row my-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="LicensePlateNumber" v-model="licensePlate" isRequired inputId="license_plate" validationRules="license-plate-required" />
|
<textboxQuestion
|
||||||
|
cmsWidgetName="LicensePlateNumber"
|
||||||
|
v-model="licensePlate"
|
||||||
|
isRequired
|
||||||
|
inputId="license_plate"
|
||||||
|
validationRules="license-plate-required"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row my-2">
|
<div class="row my-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="RegistrationZip" v-model="registrationZip" inputId="zip" mask="#####" validationRules="zip-required" />
|
<textboxQuestion
|
||||||
|
cmsWidgetName="RegistrationZip"
|
||||||
|
v-model="registrationZip"
|
||||||
|
inputId="zip"
|
||||||
|
mask="#####"
|
||||||
|
validationRules="zip-required|zip-format"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row my-2">
|
<div class="row my-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion cmsWidgetName="EmailAddress" v-model="email" inputId="email" validationRules="email-address-required|email-address-format" />
|
<textboxQuestion
|
||||||
|
cmsWidgetName="EmailAddress"
|
||||||
|
v-model="email"
|
||||||
|
inputId="email"
|
||||||
|
validationRules="email-address-required|email-address-format"
|
||||||
|
semiAggressiveValidation
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<alert class="my-3" :manualHeadline="NoServiceZipHeader" :manualCopy="NoServiceZipBody" v-if="!isRegistrationZipServicable && isVinValid && !isCarIdDifferent" alertClass="alert-danger" />
|
<alert
|
||||||
|
class="my-3"
|
||||||
|
:manualHeadline="NoServiceZipHeader"
|
||||||
|
:manualCopy="NoServiceZipBody"
|
||||||
|
v-if="!isRegistrationZipServicable && isVinValid && !isCarIdDifferent"
|
||||||
|
alertClass="alert-danger"
|
||||||
|
/>
|
||||||
<div class="row my-2">
|
<div class="row my-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion v-if="!isRegistrationZipServicable" cmsWidgetName="ServiceZip" v-model="serviceZip" inputId="serviceZip" validationRules="zip-required" />
|
<textboxQuestion
|
||||||
|
v-if="!isRegistrationZipServicable"
|
||||||
|
cmsWidgetName="ServiceZip"
|
||||||
|
v-model="serviceZip"
|
||||||
|
inputId="serviceZip"
|
||||||
|
validationRules="zip-required|zip-format"
|
||||||
|
semiAggressiveValidation
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<alert class="my-3" cmsWidgetName="NoMatchAlertWidget" v-if="!isVinValid" />
|
<alert class="my-3"
|
||||||
<alert class="my-3" :manualHeadline="MatchedDifferentVehicleAlertHeader" :manualCopy="MatchedDifferentVehicleAlertBody" v-if="isCarIdDifferent" alertClass="alert-warning" />
|
cmsWidgetName="NoMatchAlertWidget"
|
||||||
<funnelFooter ref="funnelFooter" cmsWidgetName="FunnelFooterWidget" :isForwardActionDisabled="!meta.valid" @back-clicked="backButtonAction" @ForwardClicked="forwardButtonAction" />
|
v-if="!isVinValid"
|
||||||
|
alertClass="alert-warning" />
|
||||||
|
<alert class="my-3"
|
||||||
|
:manualHeadline="MatchedDifferentVehicleAlertHeader"
|
||||||
|
:manualCopy="MatchedDifferentVehicleAlertBody"
|
||||||
|
v-if="isCarIdDifferent"
|
||||||
|
alertClass="alert-warning"
|
||||||
|
/>
|
||||||
|
<funnelFooter
|
||||||
|
ref="funnelFooter"
|
||||||
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
:isForwardActionDisabled="!meta.valid"
|
||||||
|
@back-clicked="backButtonAction"
|
||||||
|
@ForwardClicked="forwardButtonAction"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
@ -46,56 +91,25 @@ import alert from "@/ux-components/alert/alert";
|
||||||
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
|
import textboxQuestion from "@/common-components/textbox-question/textbox-question";
|
||||||
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
||||||
// Supporting files
|
// Supporting files
|
||||||
import {
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
fetchCmsContentForPage
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
} from "@/helpers/cms-content-helper";
|
|
||||||
import {
|
|
||||||
settleAllPromises
|
|
||||||
} from "@/helpers/layout-helper";
|
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import {
|
import { storeActions } from "@/constants/store-actions";
|
||||||
storeActions
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
} from "@/constants/store-actions";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import {
|
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
storeMutations
|
import { getDamageString, isGlassAvailableForCarId, } from "@/helpers/damage-helper";
|
||||||
} from "@/constants/store-mutations";
|
import { required, regex, } from "@/helpers/validation-rules";
|
||||||
import {
|
import { Form, defineRule, } from "vee-validate";
|
||||||
errorMessages
|
|
||||||
} from "@/constants/error-messages";
|
|
||||||
import {
|
|
||||||
navigateAfterSaveToHeritageFunnel
|
|
||||||
} from "@/helpers/heritage-integration/navigation-helper";
|
|
||||||
import {
|
|
||||||
getDamageString,
|
|
||||||
isGlassAvailableForCarId,
|
|
||||||
} from "@/helpers/damage-helper";
|
|
||||||
import {
|
|
||||||
required,
|
|
||||||
regex,
|
|
||||||
} from "@/helpers/validation-rules";
|
|
||||||
import {
|
|
||||||
Form,
|
|
||||||
defineRule,
|
|
||||||
} from "vee-validate";
|
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule(
|
defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED));
|
||||||
"license-plate-required",
|
|
||||||
required(errorMessages.LICENSE_PLATE_REQUIRED)
|
|
||||||
);
|
|
||||||
defineRule("zip-required", required(errorMessages.REGISTRATION_ZIP_REQUIRED));
|
defineRule("zip-required", required(errorMessages.REGISTRATION_ZIP_REQUIRED));
|
||||||
defineRule(
|
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
|
||||||
"email-address-required",
|
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
|
||||||
required(errorMessages.EMAIL_ADDRESS_REQUIRED)
|
defineRule("email-address-format", regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, errorMessages.EMAIL_ADDRESS_FORMAT));
|
||||||
);
|
|
||||||
defineRule(
|
|
||||||
"email-address-format",
|
|
||||||
regex(
|
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+).([a-zA-Z]{2,})$/,
|
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
|
||||||
)
|
|
||||||
);
|
|
||||||
export default {
|
export default {
|
||||||
name: "license-plate-lookup",
|
name: "license-plate-lookup",
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
|
@ -212,20 +226,29 @@ export default {
|
||||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
const zipValidation = this.serviceZip ?
|
|
||||||
await this.validateZip(this.serviceZip) :
|
//Call zip validation services
|
||||||
await this.validateZip(this.registrationZip);
|
const registrationZipValidationPromise = this.validateZip(this.registrationZip);
|
||||||
if (!zipValidation.data.isServiceable) {
|
const serviceZipValidationPromise = this.serviceZip ? this.validateZip(this.serviceZip) : null;
|
||||||
|
const registrationZipValidationResults = await registrationZipValidationPromise;
|
||||||
|
const serviceZipValidationResults = serviceZipValidationPromise !== null ? (await serviceZipValidationPromise) : registrationZipValidationResults;
|
||||||
|
|
||||||
|
//Handle service zip validations
|
||||||
|
if (!serviceZipValidationResults.data.isServiceable) {
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
this.isVinValid = true;
|
this.isVinValid = true;
|
||||||
this.isRegistrationZipServicable = false;
|
this.isRegistrationZipServicable = false;
|
||||||
this.isCarIdDifferent = false;
|
this.isCarIdDifferent = false;
|
||||||
this.zipToDisplay = this.serviceZip ? this.serviceZip : this.registrationZip;
|
this.zipToDisplay = this.serviceZip ? this.serviceZip : this.registrationZip;
|
||||||
return;
|
return;
|
||||||
|
} else if (!this.serviceZip) {
|
||||||
|
this.serviceZip = this.registrationZip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Lookup vin
|
||||||
const vinLookup = await this.lookupVin(
|
const vinLookup = await this.lookupVin(
|
||||||
this.licensePlate,
|
this.licensePlate,
|
||||||
zipValidation.data.state
|
registrationZipValidationResults.data.state
|
||||||
).catch(() => {
|
).catch(() => {
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
this.isVinValid = false;
|
this.isVinValid = false;
|
||||||
|
|
@ -235,6 +258,7 @@ export default {
|
||||||
this.isCarIdDifferent =
|
this.isCarIdDifferent =
|
||||||
vinLookup.data.vehicle.carId !== store.getters.vehicle.carId;
|
vinLookup.data.vehicle.carId !== store.getters.vehicle.carId;
|
||||||
|
|
||||||
|
//Handle changing car
|
||||||
if (
|
if (
|
||||||
this.isCarIdDifferent &&
|
this.isCarIdDifferent &&
|
||||||
vinLookup.data.vehicle.carId !== this.previouslyEnteredCarId
|
vinLookup.data.vehicle.carId !== this.previouslyEnteredCarId
|
||||||
|
|
@ -251,12 +275,15 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Save
|
||||||
this.updateCustomerInfo(
|
this.updateCustomerInfo(
|
||||||
vinLookup.data.vin,
|
vinLookup.data.vin,
|
||||||
vinLookup.data.vehicle,
|
vinLookup.data.vehicle,
|
||||||
zipValidation.data.state
|
registrationZipValidationResults.data.state,
|
||||||
|
serviceZipValidationResults.data.state
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Navigate
|
||||||
this.navigateForward();
|
this.navigateForward();
|
||||||
},
|
},
|
||||||
navigateForward() {
|
navigateForward() {
|
||||||
|
|
@ -281,12 +308,9 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
lookupVin(plate, state) {
|
lookupVin(plate, state) {
|
||||||
return baseMixin.methods.dispatchStoreAction(
|
return baseMixin.methods.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_PLATE,{ licensePlate: plate, licenseState: state }, false);
|
||||||
storeActions.LOOKUP_VIN_BY_PLATE,
|
|
||||||
{ licensePlate: plate, licenseState: state }
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
updateCustomerInfo(vin, vehicleInfo, registrationState) {
|
updateCustomerInfo(vin, vehicleInfo, registrationState, serviceState) {
|
||||||
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
||||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
}
|
}
|
||||||
|
|
@ -304,6 +328,7 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_STATE, registrationState);
|
store.commit(storeMutations.UPDATE_REGISTRATION_STATE, registrationState);
|
||||||
store.commit(storeMutations.UPDATE_REGISTRATION_ZIP_CODE, this.registrationZip);
|
store.commit(storeMutations.UPDATE_REGISTRATION_ZIP_CODE, this.registrationZip);
|
||||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.serviceZip);
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.serviceZip);
|
||||||
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, serviceState);
|
||||||
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.email);
|
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.email);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import store from "@/store";
|
||||||
import { validate } from "vee-validate";
|
import { validate } from "vee-validate";
|
||||||
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
||||||
import { routerParams } from "@/router/router-constants/router-params";
|
import { routerParams } from "@/router/router-constants/router-params";
|
||||||
|
import * as cookieHelper from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
|
||||||
// Mock our module for promises.
|
// Mock our module for promises.
|
||||||
jest.mock("@/helpers/layout-helper.js", () => ({
|
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||||
|
|
@ -29,6 +30,11 @@ jest.mock("@/helpers/cms-content-helper", () => ({
|
||||||
fetchCmsContentForPage: jest.fn(),
|
fetchCmsContentForPage: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Mock getFunnelCookie
|
||||||
|
jest.mock("@/helpers/heritage-integration/cookie-helper", () => ({
|
||||||
|
getFunnelCookie: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
// Mock Store
|
// Mock Store
|
||||||
jest.mock("@/store", () => ({
|
jest.mock("@/store", () => ({
|
||||||
commit: jest.fn(),
|
commit: jest.fn(),
|
||||||
|
|
@ -653,6 +659,10 @@ describe("vehicle-damage.vue", () => {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("vehicle-damage.vue wasDelayedClaimRegistration", () => {
|
||||||
|
test.todo("if wasDelayedClaimRegistration, should hide back button")
|
||||||
|
});
|
||||||
|
|
||||||
// THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE
|
// THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE
|
||||||
// BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST
|
// BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST
|
||||||
//
|
//
|
||||||
|
|
@ -741,6 +751,7 @@ function setupMocks({pageHeaderWidgetHeaderText, mountOptionsMockData}) {
|
||||||
|
|
||||||
settleAllPromises.mockImplementation(() => apiPromise);
|
settleAllPromises.mockImplementation(() => apiPromise);
|
||||||
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
|
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
|
||||||
|
cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie").mockReturnValue({});
|
||||||
|
|
||||||
//Mock damage initialize methods
|
//Mock damage initialize methods
|
||||||
damageLocationQuestion.methods = {
|
damageLocationQuestion.methods = {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
:selectedDamageLocations="selectedDamageLocations"
|
:selectedDamageLocations="selectedDamageLocations"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-5"
|
||||||
cmsWidgetName="HasReplacementConflict"
|
cmsWidgetName="HasReplacementConflict"
|
||||||
v-show="hasRepairReplaceConflict"
|
v-show="hasRepairReplaceConflict"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
|
|
@ -87,6 +87,7 @@ import { required } from "@/helpers/validation-rules";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
||||||
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
||||||
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
|
|
@ -405,7 +406,7 @@ export default {
|
||||||
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
|
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
|
||||||
},
|
},
|
||||||
shouldHideBackButton(){
|
shouldHideBackButton(){
|
||||||
return this.$store.getters.payment.insuranceCoverage.isVerified;
|
return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-3"
|
||||||
cmsWidgetName="NoReplacementAvailableError"
|
cmsWidgetName="NoReplacementAvailableError"
|
||||||
v-show="showNoReplacementAvailableError"
|
v-if="showNoReplacementAvailableError"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
:isDismissible="false"
|
:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
|
|
@ -30,9 +30,9 @@
|
||||||
isRequired
|
isRequired
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="mt-5"
|
||||||
cmsWidgetName="SplitSingleConflict"
|
cmsWidgetName="SplitSingleConflict"
|
||||||
v-show="hasSplitSingleConflict"
|
v-if="hasSplitSingleConflict"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
:isDismissible="false"
|
:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,10 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_STYLE, null);
|
store.commit(storeMutations.UPDATE_STYLE, null);
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, null);
|
store.commit(storeMutations.UPDATE_CAR_ID, null);
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null);
|
store.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null);
|
||||||
|
|
||||||
// Invokes
|
// Invokes
|
||||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,10 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_STYLE, null);
|
store.commit(storeMutations.UPDATE_STYLE, null);
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, null);
|
store.commit(storeMutations.UPDATE_CAR_ID, null);
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null);
|
store.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null);
|
||||||
|
|
||||||
// Invokes
|
// Invokes
|
||||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_IS_REPAIR, null);
|
store.commit(storeMutations.UPDATE_IS_REPAIR, null);
|
||||||
store.commit(storeMutations.UPDATE_NUMBER_OF_CHIPS, null);
|
store.commit(storeMutations.UPDATE_NUMBER_OF_CHIPS, null);
|
||||||
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []);
|
store.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, []);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,10 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_STYLE, null);
|
store.commit(storeMutations.UPDATE_STYLE, null);
|
||||||
store.commit(storeMutations.UPDATE_CAR_ID, null);
|
store.commit(storeMutations.UPDATE_CAR_ID, null);
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null);
|
store.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, null);
|
||||||
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, null);
|
||||||
|
|
||||||
// Invokes
|
// Invokes
|
||||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ export default {
|
||||||
font-size: .875rem;
|
font-size: .875rem;
|
||||||
color: $gray-600;
|
color: $gray-600;
|
||||||
}
|
}
|
||||||
|
li {
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
a {
|
a {
|
||||||
font-size: .875rem;
|
font-size: .875rem;
|
||||||
}
|
}
|
||||||
|
|
@ -70,6 +73,7 @@ export default {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
img {
|
img {
|
||||||
|
max-width: 420px;
|
||||||
width: 117%;
|
width: 117%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
/>
|
/>
|
||||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
<div class="fade-on-route-transition sub-container make-tall">
|
<div class="fade-on-route-transition sub-container make-tall">
|
||||||
<div class="row my-2">
|
<div class="row mt-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<textboxQuestion
|
<textboxQuestion
|
||||||
cmsWidgetName="VinNumber"
|
cmsWidgetName="VinNumber"
|
||||||
|
|
@ -24,10 +24,11 @@
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="vin-required|vin-format"
|
validationRules="vin-required|vin-format"
|
||||||
:isDisabled="isVinFieldReadOnly"
|
:isDisabled="isVinFieldReadOnly"
|
||||||
|
maxLength="17"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row my-2">
|
<div class="row mb-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<vinInformation />
|
<vinInformation />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -41,7 +42,7 @@
|
||||||
mask="#####"
|
mask="#####"
|
||||||
isRequired
|
isRequired
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="zip-required"
|
validationRules="zip-required|zip-format"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -54,18 +55,19 @@
|
||||||
isRequired
|
isRequired
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
validationRules="email-address-required|email-address-format"
|
validationRules="email-address-required|email-address-format"
|
||||||
|
semiAggressiveValidation
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-4"
|
||||||
v-model="customAlertData"
|
v-model="customAlertData"
|
||||||
v-if="noMatchAlert"
|
v-if="noMatchAlert"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
cmsWidgetName="NoMatchAlertWidget"
|
cmsWidgetName="NoMatchAlertWidget"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-4"
|
||||||
:manualHeadline="PerfectMatchNewVinAlertReadOnlyHeader"
|
:manualHeadline="PerfectMatchNewVinAlertReadOnlyHeader"
|
||||||
:manualCopy="PerfectMatchNewVinAlertReadOnlyBody"
|
:manualCopy="PerfectMatchNewVinAlertReadOnlyBody"
|
||||||
v-model="customAlertData"
|
v-model="customAlertData"
|
||||||
|
|
@ -73,15 +75,15 @@
|
||||||
alertClass="alert-success"
|
alertClass="alert-success"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-4"
|
||||||
:manualHeadline="MatchedDifferentVehicleAlertHeader"
|
:manualHeadline="MatchedDifferentVehicleAlertHeader"
|
||||||
:manualCopy="MatchedDifferentVehicleAlertBody"
|
:manualCopy="MatchedDifferentVehicleAlertBody"
|
||||||
v-model="customAlertData"
|
v-model="customAlertData"
|
||||||
v-if="isCarIdDifferent"
|
v-if="isCarIdDifferent && !vinNotFound && !perfectMatchNewVinAlert"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-warning"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-4"
|
||||||
:manualHeadline="NoServiceZipHeader"
|
:manualHeadline="NoServiceZipHeader"
|
||||||
:manualCopy="NoServiceZipBody"
|
:manualCopy="NoServiceZipBody"
|
||||||
v-model="customAlertData"
|
v-model="customAlertData"
|
||||||
|
|
@ -89,18 +91,19 @@
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-4"
|
||||||
v-model="customAlertData"
|
v-model="customAlertData"
|
||||||
v-if="vinNotFound"
|
v-if="vinNotFound"
|
||||||
alertClass="alert-warning"
|
alertClass="alert-danger"
|
||||||
cmsWidgetName="VinNotFound"
|
cmsWidgetName="VinNotFound"
|
||||||
/>
|
/>
|
||||||
<alert
|
<alert
|
||||||
class="my-3"
|
class="my-4"
|
||||||
|
:manualHeadline="PerfectMatchNewVinAlertHeader"
|
||||||
|
:manualCopy="PerfectMatchNewVinAlertBody"
|
||||||
v-model="customAlertData"
|
v-model="customAlertData"
|
||||||
v-if="perfectMatchNewVinAlert"
|
v-if="perfectMatchNewVinAlert && !noServiceZip && !vinNotFound && meta.valid && !isVinFieldReadOnly"
|
||||||
alertClass="alert-success"
|
alertClass="alert-success"
|
||||||
cmsWidgetName="PerfectMatchNewVinAlert"
|
|
||||||
/>
|
/>
|
||||||
<funnelFooter
|
<funnelFooter
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
|
@ -137,25 +140,15 @@ import { getDamageString, getIsWindshieldOnly, isGlassAvailableForCarId } from "
|
||||||
import { required, regex } from "@/helpers/validation-rules";
|
import { required, regex } from "@/helpers/validation-rules";
|
||||||
import { Form, defineRule } from "vee-validate";
|
import { Form, defineRule } from "vee-validate";
|
||||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
||||||
defineRule(
|
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
|
||||||
"email-address-required",
|
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
|
||||||
required(errorMessages.EMAIL_ADDRESS_REQUIRED)
|
defineRule("email-address-format", regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, errorMessages.EMAIL_ADDRESS_FORMAT));
|
||||||
);
|
|
||||||
defineRule(
|
|
||||||
"email-address-format",
|
|
||||||
regex(
|
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+).([a-zA-Z]{2,})$/,
|
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
|
||||||
)
|
|
||||||
);
|
|
||||||
defineRule("vin-required", required(errorMessages.VIN_REQUIRED));
|
defineRule("vin-required", required(errorMessages.VIN_REQUIRED));
|
||||||
defineRule(
|
defineRule("vin-format", regex(/^[a-hA-Hj-nJ-NpPr-zR-Z0-9]{17}$/, errorMessages.VIN_FORMAT));
|
||||||
"vin-format",
|
|
||||||
regex(/^[A-HJ-NPR-Z0-9]{17}$/, errorMessages.VIN_FORMAT)
|
|
||||||
);
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "vin-lookup",
|
name: "vin-lookup",
|
||||||
|
|
@ -192,12 +185,21 @@ export default {
|
||||||
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
|
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.attachCustomEvents();
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
vin() {
|
||||||
|
this.vinNotFound = false;
|
||||||
|
this.$refs.funnelFooter.updateButtonText(
|
||||||
|
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
perfectMatchNewVinAlert() {
|
perfectMatchNewVinAlert() {
|
||||||
const isVinPerfectMatch = this.vinPopulatedOnPageLoad && this.vin === this.getVinFromStore();
|
const isVinPerfectMatch = this.vinPopulatedOnPageLoad && this.vin === this.getVinFromStore();
|
||||||
if (isVinPerfectMatch) {
|
this.updateIsCarIdDifferent(isVinPerfectMatch);
|
||||||
this.isCarIdDifferent = false;
|
|
||||||
}
|
|
||||||
return isVinPerfectMatch;
|
return isVinPerfectMatch;
|
||||||
},
|
},
|
||||||
MatchedDifferentVehicleAlertHeader(){
|
MatchedDifferentVehicleAlertHeader(){
|
||||||
|
|
@ -236,7 +238,7 @@ export default {
|
||||||
getIsWindshieldOnly())
|
getIsWindshieldOnly())
|
||||||
},
|
},
|
||||||
isVinFieldReadOnly(){
|
isVinFieldReadOnly(){
|
||||||
return this.$store.getters.payment.insuranceCoverage.isVerified;
|
return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -264,11 +266,16 @@ export default {
|
||||||
this.pushEventToGA(
|
this.pushEventToGA(
|
||||||
this.$route.query[this.queryStrings.FMG_PAGE],
|
this.$route.query[this.queryStrings.FMG_PAGE],
|
||||||
this.GaActions.SUBMITTED,
|
this.GaActions.SUBMITTED,
|
||||||
this.GaLabels.VINLOOKUP,
|
this.GaLabels.VIN_LOOKUP,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
updateIsCarIdDifferent(isVinPerfectMatch){
|
||||||
|
if (isVinPerfectMatch) {
|
||||||
|
this.isCarIdDifferent = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
backButtonAction() {
|
backButtonAction() {
|
||||||
if (store.getters.vehicle.vin) {
|
if (store.getters.vehicle.vin) {
|
||||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK_WITH_VIN, this.$route);
|
this.$router.navigate(this.navigationScenarios.CLICKED_BACK_WITH_VIN, this.$route);
|
||||||
|
|
@ -307,7 +314,7 @@ export default {
|
||||||
this.isCarIdDifferent = true;
|
this.isCarIdDifferent = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.updateStore(vehicleLookupResponse.data);
|
this.updateStore(vehicleLookupResponse.data, zipValidationResponse.data);
|
||||||
this.navigateForward();
|
this.navigateForward();
|
||||||
},
|
},
|
||||||
navigateForward(){
|
navigateForward(){
|
||||||
|
|
@ -331,7 +338,7 @@ export default {
|
||||||
{ vin }
|
{ vin }
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
updateStore(carInfo) {
|
updateStore(carInfo, zipInfo) {
|
||||||
if(this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle){
|
if(this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle){
|
||||||
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
store.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
}
|
}
|
||||||
|
|
@ -346,6 +353,7 @@ export default {
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, carInfo.imageVifNumber);
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, carInfo.imageVifNumber);
|
||||||
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, carInfo.imageVifNumber);
|
store.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, carInfo.imageVifNumber);
|
||||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.zip);
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.zip);
|
||||||
|
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, zipInfo.state);
|
||||||
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.email);
|
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.email);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,18 @@ import baseMixin from "@/mixins/base-mixin";
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
logPageView(pageEvent) {
|
logPageView(pageEvent) {
|
||||||
|
// if the user does not have a session id from the content site, do not log.
|
||||||
|
const sid = getSessionIdValue();
|
||||||
|
if (sid === '00000000-0000-0000-0000-000000000000' || sid == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const currentPageName = getPageNameByQueryString();
|
const currentPageName = getPageNameByQueryString();
|
||||||
var payload = {
|
var payload = {
|
||||||
userId: getDeviceIdValue(),
|
userId: getDeviceIdValue(),
|
||||||
sessionKey: getSessionKeyValue(),
|
sessionKey: getSessionKeyValue(),
|
||||||
pageName: currentPageName,
|
pageName: currentPageName,
|
||||||
sessionId: getSessionIdValue(),
|
sessionId: sid,
|
||||||
action: '',
|
action: '',
|
||||||
event: pageEvent,
|
event: pageEvent,
|
||||||
shouldUseSessionId: true,
|
shouldUseSessionId: true,
|
||||||
|
|
@ -24,12 +30,18 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
logCustomEvent(category, action, label, value) {
|
logCustomEvent(category, action, label, value) {
|
||||||
|
// if the user does not have a session id from the content site, do not log.
|
||||||
|
const sid = getSessionIdValue();
|
||||||
|
if (sid === '00000000-0000-0000-0000-000000000000' || sid == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const currentPageName = getPageNameByQueryString();
|
const currentPageName = getPageNameByQueryString();
|
||||||
var payload = {
|
var payload = {
|
||||||
userId: getDeviceIdValue(),
|
userId: getDeviceIdValue(),
|
||||||
sessionKey: getSessionKeyValue(),
|
sessionKey: getSessionKeyValue(),
|
||||||
pageName: currentPageName,
|
pageName: currentPageName,
|
||||||
sessionId: getSessionIdValue(),
|
sessionId: sid,
|
||||||
category: category,
|
category: category,
|
||||||
action: action,
|
action: action,
|
||||||
label: label,
|
label: label,
|
||||||
|
|
@ -97,8 +109,9 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
prependActionToMethod(object, method, actionToPrepend) {
|
prependActionToMethod(object, method, actionToPrepend) {
|
||||||
const baseMethod = object[method.name];
|
const baseMethodName = method.name.startsWith('bound ') ? method.name.substring(6) : method.name ;
|
||||||
object[method.name] = function () {
|
const baseMethod = object[baseMethodName];
|
||||||
|
object[baseMethodName] = function () {
|
||||||
actionToPrepend.apply(this, arguments);
|
actionToPrepend.apply(this, arguments);
|
||||||
return baseMethod.apply(object, arguments);
|
return baseMethod.apply(object, arguments);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import analyticsMixin from "@/mixins/analytics-mixin";
|
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||||
import { setupMocksForJsFiles } from "@/helpers/unit-test-helper.js";
|
import { setupMocksForJsFiles, setupCookies } from "@/helpers/unit-test-helper.js";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
|
||||||
describe("analyticsMixin.js", () => {
|
describe("analyticsMixin.js", () => {
|
||||||
|
|
@ -14,6 +14,12 @@ describe("analyticsMixin.js", () => {
|
||||||
}
|
}
|
||||||
const mocks = setupMocksForJsFiles(mockData);
|
const mocks = setupMocksForJsFiles(mockData);
|
||||||
|
|
||||||
|
const testCookieValue = {
|
||||||
|
sid: '10000000-0000-0000-0000-000000000001'
|
||||||
|
}
|
||||||
|
|
||||||
|
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
|
||||||
|
|
||||||
analyticsMixin.methods.logPageView(type, payload);
|
analyticsMixin.methods.logPageView(type, payload);
|
||||||
|
|
||||||
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
|
expect(mocks.baseMixin.methods.dispatchStoreAction).toBeCalled();
|
||||||
|
|
@ -107,4 +113,17 @@ describe("analyticsMixin.js", () => {
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Obj is not null after action prepended", () => {
|
||||||
|
//Arrange
|
||||||
|
const obj = {baseMethodName:"testMethodName", data:"testData"};
|
||||||
|
const method = {name:"testMethodName", data:"testData" }
|
||||||
|
const action = "testAction";
|
||||||
|
|
||||||
|
//Act
|
||||||
|
analyticsMixin.methods.prependActionToMethod(obj, method, action);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(obj!=null);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -42,6 +42,10 @@ export default {
|
||||||
el && el.focus();
|
el && el.focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getFooterInfoBoxHeight() {
|
||||||
|
const footerInfoBox = document.querySelector(".footer #infoBox");
|
||||||
|
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
storeActions() {
|
storeActions() {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import analyticsMixin from "@/mixins/analytics-mixin";
|
||||||
// Components
|
// Components
|
||||||
import ComponentTest from "@/layouts/component-test/component-test.vue";
|
import ComponentTest from "@/layouts/component-test/component-test.vue";
|
||||||
import FormTest from "@/layouts/form-test/form-test.vue";
|
import FormTest from "@/layouts/form-test/form-test.vue";
|
||||||
|
import Modal from "@/common-components/loading-modal/loading-modal.vue";
|
||||||
|
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
|
|
@ -34,6 +35,11 @@ const routes = [
|
||||||
name: "FormTest",
|
name: "FormTest",
|
||||||
component: FormTest,
|
component: FormTest,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/loading-modal", // This is a temporary route for testing.
|
||||||
|
name: "Modal",
|
||||||
|
component: Modal,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
name: "root",
|
name: "root",
|
||||||
|
|
@ -214,13 +220,6 @@ function navigateToUrl(url, optionalQuery = {}) {
|
||||||
externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
|
externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
// TEMP CODE FOR TESTING WITH SPECIFIC EXPERIMENTS //
|
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
if (externalUrl.search.indexOf("corid=") != -1)
|
|
||||||
externalUrl.search = externalUrl.search + '&experiments=CollectEmailOnQuote=CollectEmailOnQuote_V1=YesCollectEmail_TEST1=true,RemoveServiceAreaPage=ServAreaRemoval_V7=ServAreaNoRemove_V7_TEST=true,VINeducationV2=VINeducation_V2=NoShowVINmodalV2_CONTROL=true,ServicePackages=ServicePackages_V1=NoShowPackages_CONTROL=true,PhotoUploadRedesign=PhotoUploadRedesign_V1=CurrentPhotoUpload_CONTROL=true,ScheduleDetailsServiceType=ScheduleBeforeServiceType_V1=ServTypeThenSched_CONTROL=true';
|
|
||||||
///////////// END TEMP CODE /////////////////////////
|
|
||||||
|
|
||||||
window.location.assign(externalUrl);
|
window.location.assign(externalUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,9 @@ export const mutations = {
|
||||||
updateServiceLocationZipCode(state, serviceLocationZip){
|
updateServiceLocationZipCode(state, serviceLocationZip){
|
||||||
state.order.serviceLocation.zipCode = serviceLocationZip;
|
state.order.serviceLocation.zipCode = serviceLocationZip;
|
||||||
},
|
},
|
||||||
|
updateServiceLocationState(state, serviceLocationState){
|
||||||
|
state.order.serviceLocation.state = serviceLocationState;
|
||||||
|
},
|
||||||
updateRegistrationFirstName(state, firstName){
|
updateRegistrationFirstName(state, firstName){
|
||||||
state.order.vehicle.registration.firstName = firstName;
|
state.order.vehicle.registration.firstName = firstName;
|
||||||
},
|
},
|
||||||
|
|
@ -190,6 +193,10 @@ export const mutations = {
|
||||||
state.order.vehicle.style = null;
|
state.order.vehicle.style = null;
|
||||||
state.order.vehicle.carId = null;
|
state.order.vehicle.carId = null;
|
||||||
state.order.vehicle.category = null;
|
state.order.vehicle.category = null;
|
||||||
|
state.order.vehicle.vin = null;
|
||||||
|
state.order.vehicle.imageUrl = null;
|
||||||
|
state.order.vehicle.imageVifNumber = null;
|
||||||
|
state.order.vehicle.imageColor = null;
|
||||||
},
|
},
|
||||||
resetDamageState(state) {
|
resetDamageState(state) {
|
||||||
state.order.damage.isRepair = null;
|
state.order.damage.isRepair = null;
|
||||||
|
|
@ -566,9 +573,9 @@ export const actions = {
|
||||||
state: order.serviceLocation.state,
|
state: order.serviceLocation.state,
|
||||||
zipCode: order.serviceLocation.zipCode
|
zipCode: order.serviceLocation.zipCode
|
||||||
},
|
},
|
||||||
referralNumber: order.referralNumber,
|
referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place
|
||||||
referralDate: order.referralDate,
|
referralDate: order.referralDate,
|
||||||
accountNumber: order.accountNumber
|
accountNumber: order.accountNumber?.toString()
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -578,10 +585,10 @@ export const actions = {
|
||||||
method: endpoints.LoadOrder.method,
|
method: endpoints.LoadOrder.method,
|
||||||
endpoint: endpoints.LoadOrder.url,
|
endpoint: endpoints.LoadOrder.url,
|
||||||
payload: {
|
payload: {
|
||||||
referralNumber: referralNumber,
|
referralNumber: referralNumber?.toString(),
|
||||||
referralDate: referralDate,
|
referralDate: referralDate,
|
||||||
referralCorrelationId: referralCorrelationId,
|
referralCorrelationId: referralCorrelationId,
|
||||||
accountNumber: accountNumber
|
accountNumber: accountNumber?.toString()
|
||||||
},
|
},
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
context.commit(storeMutations.RESET_STATE);
|
context.commit(storeMutations.RESET_STATE);
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.route-fade-enter-active .fade-on-route-transition {
|
.route-fade-enter-active .fade-on-route-transition {
|
||||||
transition: opacity 0.8s ease;
|
transition: opacity 0.2s ease-out; //This duration should be kept in sync with the app.vue <transition> element attribute
|
||||||
}
|
}
|
||||||
|
|
||||||
.route-fade-leave-active .fade-on-route-transition {
|
.route-fade-leave-active .fade-on-route-transition {
|
||||||
transition: opacity 0.3s ease;
|
transition: opacity 0.2s ease-in; //This duration should be kept in sync with the app.vue <transition> element attribute
|
||||||
}
|
}
|
||||||
|
|
||||||
.route-fade-enter-from .fade-on-route-transition,
|
.route-fade-enter-from .fade-on-route-transition,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ html {
|
||||||
&.list-button,
|
&.list-button,
|
||||||
&.list-card,
|
&.list-card,
|
||||||
&.list-card.list-button {
|
&.list-card.list-button {
|
||||||
|
border: none;
|
||||||
color: $red;
|
color: $red;
|
||||||
input[type=checkbox]:focus + label,
|
input[type=checkbox]:focus + label,
|
||||||
input[type=radio]:focus + label {
|
input[type=radio]:focus + label {
|
||||||
|
|
@ -13,10 +14,11 @@ html {
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: 0px 0px 0px 4px $red-200;
|
box-shadow: 0px 0px 0px 4px $red-200;
|
||||||
border-radius: 10px;
|
border-radius: .5rem;
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
border: 1px solid $red;
|
border: 1px solid $red;
|
||||||
|
border-radius: .5rem;
|
||||||
}
|
}
|
||||||
label:hover {
|
label:hover {
|
||||||
box-shadow: 0px 0px 0px 4px $red-200;
|
box-shadow: 0px 0px 0px 4px $red-200;
|
||||||
|
|
@ -51,12 +53,21 @@ html {
|
||||||
}
|
}
|
||||||
&.textbox-question,
|
&.textbox-question,
|
||||||
&.dropdown-question {
|
&.dropdown-question {
|
||||||
|
input:hover {
|
||||||
|
box-shadow: 0px 0px 0px 4px $red-200;
|
||||||
|
border-radius: .5rem;
|
||||||
|
border: 1px solid $red;
|
||||||
|
}
|
||||||
|
input:focus {
|
||||||
|
box-shadow: 0 0 0 2.5px $red;
|
||||||
|
}
|
||||||
p {
|
p {
|
||||||
color: $red;
|
color: $red;
|
||||||
}
|
}
|
||||||
input,
|
input,
|
||||||
select {
|
select {
|
||||||
border: 1px solid $red;
|
border: 1px solid transparent;
|
||||||
|
box-shadow: 0 0 0 1px $red;
|
||||||
&:focus {
|
&:focus {
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
@ -77,12 +88,14 @@ html {
|
||||||
border: 1px solid $gray-500;
|
border: 1px solid $gray-500;
|
||||||
input:not(:focus) {
|
input:not(:focus) {
|
||||||
+ label {
|
+ label {
|
||||||
|
border: none;
|
||||||
box-shadow: 0 0 0 1px $gray-500;
|
box-shadow: 0 0 0 1px $gray-500;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input:checked:focus {
|
input:checked:focus {
|
||||||
+ label {
|
+ label {
|
||||||
|
border: none;
|
||||||
box-shadow: 0 0 0 2.5px $blue;
|
box-shadow: 0 0 0 2.5px $blue;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
}
|
}
|
||||||
|
|
@ -114,8 +127,6 @@ html {
|
||||||
color: $red;
|
color: $red;
|
||||||
font-size: .875rem;
|
font-size: .875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
height: 1.5rem;
|
|
||||||
margin-top: .25rem !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-test-invalid {
|
.form-test-invalid {
|
||||||
|
|
@ -129,7 +140,6 @@ html {
|
||||||
&.btn.btn-primary:hover,
|
&.btn.btn-primary:hover,
|
||||||
&.btn.btn-primary:focus,
|
&.btn.btn-primary:focus,
|
||||||
&.btn.btn-primary:focus-visible {
|
&.btn.btn-primary:focus-visible {
|
||||||
color: $gray !important;
|
|
||||||
background: $gray-200;
|
background: $gray-200;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ describe("alert.vue", () => {
|
||||||
|
|
||||||
const mockMixin = {
|
const mockMixin = {
|
||||||
methods: {
|
methods: {
|
||||||
getCmsContent: jest.fn()
|
getCmsContent: jest.fn(),
|
||||||
|
getFooterInfoBoxHeight: jest.fn(()=> 80),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,15 +5,17 @@
|
||||||
:class="[isDismissible ? 'alert-dismissible' : '', this.alertClass]"
|
:class="[isDismissible ? 'alert-dismissible' : '', this.alertClass]"
|
||||||
>
|
>
|
||||||
<p class="m-0 fw-bold alert-heading">{{ alertHeadline }}</p>
|
<p class="m-0 fw-bold alert-heading">{{ alertHeadline }}</p>
|
||||||
<p v-if="splitAlertCopyForLink.length">
|
<template v-for="paragraph in splitAlertCopyForParagraphTag" :key="paragraph">
|
||||||
<template v-for="copy in splitAlertCopyForLink" :key="copy">
|
<p class="m-0 text-body small" v-if="!doesCopyContainRouterLink(paragraph)" v-html="paragraph"></p>
|
||||||
<span v-if="copy.includes('routerLink:')" class="m-0 text-body">
|
<p class="m-0 text-body small" v-else>
|
||||||
<router-link :to="{query: {fmgPage: `${copy.split(':')[1].split(',')[0]}`}, name: 'root'}">{{ copy.split(':')[1].split(',')[1] }}</router-link>
|
<template v-for="copy in splitCopyForRouterLink(paragraph)" :key="copy">
|
||||||
|
<span v-if="!doesCopyContainRouterLink(copy)" v-html="copy"></span>
|
||||||
|
<span v-else>
|
||||||
|
<router-link :to="{query: {fmgPage: `${getRouterLinkRouteFromCopy(copy)}`}, name: 'root'}">{{ getRouterLinkDisplayTextFromCopy(copy) }}</router-link>
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="m-0 text-body" v-html="copy"></span>
|
|
||||||
</template>
|
</template>
|
||||||
</p>
|
</p>
|
||||||
<p v-else class="m-0 text-body" v-html="alertCopy"></p>
|
</template>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn-close p-2"
|
class="btn-close p-2"
|
||||||
|
|
@ -50,6 +52,10 @@ export default {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
manualHeadline: String,
|
manualHeadline: String,
|
||||||
manualCopy: String,
|
manualCopy: String,
|
||||||
|
shouldScrollToOnMount: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
alertHeadline(){
|
alertHeadline(){
|
||||||
|
|
@ -58,11 +64,60 @@ export default {
|
||||||
alertCopy(){
|
alertCopy(){
|
||||||
return this.cmsWidgetName ? this.getCmsContent(this.cmsWidgetName, 'BodyText') : this.manualCopy;
|
return this.cmsWidgetName ? this.getCmsContent(this.cmsWidgetName, 'BodyText') : this.manualCopy;
|
||||||
},
|
},
|
||||||
splitAlertCopyForLink(){
|
splitAlertCopyForParagraphTag(){
|
||||||
// Splits content when brackets are found in text so that text can be looped through and router-link can be injected when needed
|
// splits the alertCopy on <p ... > (with or without attributes) and </p>
|
||||||
return this.alertCopy.split(/{(.*?)}/g);
|
// filter removes empty strings that are a result of string.split with regex
|
||||||
|
return this.alertCopy.split(/(?:<p(?:.*?)>)|(?:<\/p>)/g).filter(paragraph => paragraph !== "");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
doesCopyContainRouterLink(copy) {
|
||||||
|
return copy.includes('routerLink:');
|
||||||
|
},
|
||||||
|
splitCopyForRouterLink(copy){
|
||||||
|
// splits copy on { ... } such as {routerlink: ...}
|
||||||
|
return copy.split(/{(.*?)}/g);
|
||||||
|
},
|
||||||
|
getRouterLinkRouteFromCopy(copy){
|
||||||
|
// sample input: {routerLink:estimate,provide your VIN}
|
||||||
|
// first split would return 'estimate,provide your VIN'
|
||||||
|
// second split would return 'estimate'
|
||||||
|
return copy.split(':')[1].split(',')[0];
|
||||||
|
},
|
||||||
|
getRouterLinkDisplayTextFromCopy(copy){
|
||||||
|
// sample input: {routerLink:estimate,provide your VIN}
|
||||||
|
// first split would return 'estimate,provide your VIN'
|
||||||
|
// second split would return 'provide your VIN'
|
||||||
|
return copy.split(':')[1].split(',')[1];
|
||||||
|
},
|
||||||
|
ensureAlertIsInViewPort() {
|
||||||
|
if (this.shouldScrollToOnMount && this.$el.style.display != 'none') {
|
||||||
|
var footerHeight = this.getFooterInfoBoxHeight();
|
||||||
|
if (!this.isAlertInViewport(footerHeight)) {
|
||||||
|
this.scrollContainerToAlert(footerHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
isAlertInViewport(footerHeight) {
|
||||||
|
const rect = this.$el.getBoundingClientRect();
|
||||||
|
return (
|
||||||
|
rect.top >= 0 &&
|
||||||
|
// remove footerHeight from window height to avoid items being hidden behind footer
|
||||||
|
rect.bottom <= (window.innerHeight - footerHeight || document.documentElement.clientHeight - footerHeight)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
scrollContainerToAlert(footerHeight) {
|
||||||
|
// alert position on page + height of alert + footer height
|
||||||
|
var scrollToHeight = this.$el.scrollHeight + this.$el.offsetHeight + footerHeight;
|
||||||
|
// find the div wrapped by the form element - this is the scrollable container
|
||||||
|
// should be a more future-proof selector in case of CSS class changes
|
||||||
|
var pageContainerScrollable = document.querySelector('form > div');
|
||||||
|
pageContainerScrollable.scrollTo(0, scrollToHeight);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.ensureAlertIsInViewPort();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import listButtonHorizontal from "./list-button-horizontal";
|
import listButtonHorizontal from "./list-button-horizontal";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
|
import { GaActions } from "@/constants/analytics";
|
||||||
|
|
||||||
describe("list-button-horizontal.vue", () => {
|
describe("list-button-horizontal.vue", () => {
|
||||||
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
||||||
|
|
@ -90,6 +91,13 @@ describe("list-button-horizontal.vue", () => {
|
||||||
it("Should return loader enabled true", async () => {
|
it("Should return loader enabled true", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
const wrapper = shallowMount(listButtonHorizontal, {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
'$route': { query: { fmgPage: 'page-name' } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
}
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
selectingInitiatesLoad: true,
|
selectingInitiatesLoad: true,
|
||||||
},
|
},
|
||||||
|
|
@ -112,6 +120,13 @@ describe("list-button-horizontal.vue", () => {
|
||||||
it("Should return loader color", async () => {
|
it("Should return loader color", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
const wrapper = shallowMount(listButtonHorizontal, {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
'$route': { query: { fmgPage: 'page-name' } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
}
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
loaderColor: "blue",
|
loaderColor: "blue",
|
||||||
selectingInitiatesLoad: true,
|
selectingInitiatesLoad: true,
|
||||||
|
|
@ -135,6 +150,13 @@ describe("list-button-horizontal.vue", () => {
|
||||||
it("Should return loader position", async () => {
|
it("Should return loader position", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
const wrapper = shallowMount(listButtonHorizontal, {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
'$route': { query: { fmgPage: 'page-name' } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
}
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
loaderPosition: "right",
|
loaderPosition: "right",
|
||||||
selectingInitiatesLoad: true,
|
selectingInitiatesLoad: true,
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { useField } from "vee-validate";
|
import { useField } from "vee-validate";
|
||||||
import loader from "@/ux-components/loader/loader";
|
import loader from "@/ux-components/loader/loader";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "listButtonHorizontal",
|
name: "listButtonHorizontal",
|
||||||
|
|
@ -91,6 +92,10 @@ export default {
|
||||||
: this.selectedValues[0];
|
: this.selectedValues[0];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
unmounted() { // needed to clear this button's selectedValues if it is removed
|
||||||
|
this.checkValue = false;
|
||||||
|
this.handleCheckChange();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayLoader() {
|
displayLoader() {
|
||||||
this.isLoaderDisplayed = true;
|
this.isLoaderDisplayed = true;
|
||||||
|
|
@ -116,6 +121,7 @@ export default {
|
||||||
this.handleCheckChange();
|
this.handleCheckChange();
|
||||||
}
|
}
|
||||||
this.handleChange(this.value);
|
this.handleChange(this.value);
|
||||||
|
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.value.toString(), true);
|
||||||
},
|
},
|
||||||
handleCheckChange() {
|
handleCheckChange() {
|
||||||
const emitEvent = {
|
const emitEvent = {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import listButton from "./list-button";
|
import listButton from "./list-button";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
|
import { GaActions } from "@/constants/analytics";
|
||||||
|
|
||||||
describe("list-button.vue", () => {
|
describe("list-button.vue", () => {
|
||||||
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
||||||
|
|
@ -90,6 +91,13 @@ describe("list-button.vue", () => {
|
||||||
it("Should return loader enabled true", async () => {
|
it("Should return loader enabled true", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listButton, {
|
const wrapper = shallowMount(listButton, {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
'$route': { query: { fmgPage: 'page-name' } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
}
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
selectingInitiatesLoad: true,
|
selectingInitiatesLoad: true,
|
||||||
},
|
},
|
||||||
|
|
@ -109,6 +117,13 @@ describe("list-button.vue", () => {
|
||||||
it("Should return loader color", async () => {
|
it("Should return loader color", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listButton, {
|
const wrapper = shallowMount(listButton, {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
'$route': { query: { fmgPage: 'page-name' } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
}
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
loaderColor: "blue",
|
loaderColor: "blue",
|
||||||
selectingInitiatesLoad: true,
|
selectingInitiatesLoad: true,
|
||||||
|
|
@ -128,6 +143,13 @@ describe("list-button.vue", () => {
|
||||||
it("Should return loader position", async () => {
|
it("Should return loader position", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listButton, {
|
const wrapper = shallowMount(listButton, {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
'$route': { query: { fmgPage: 'page-name' } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
}
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
loaderPosition: "right",
|
loaderPosition: "right",
|
||||||
selectingInitiatesLoad: true,
|
selectingInitiatesLoad: true,
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { useField } from "vee-validate";
|
import { useField } from "vee-validate";
|
||||||
import loader from "@/ux-components/loader/loader";
|
import loader from "@/ux-components/loader/loader";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "listButton",
|
name: "listButton",
|
||||||
|
|
@ -91,6 +92,10 @@ export default {
|
||||||
: this.selectedValues[0];
|
: this.selectedValues[0];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
unmounted() { // needed to clear this button's selectedValues if it is removed
|
||||||
|
this.checkValue = false;
|
||||||
|
this.handleCheckChange();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayLoader() {
|
displayLoader() {
|
||||||
this.isLoaderDisplayed = true;
|
this.isLoaderDisplayed = true;
|
||||||
|
|
@ -116,6 +121,7 @@ export default {
|
||||||
this.handleCheckChange();
|
this.handleCheckChange();
|
||||||
}
|
}
|
||||||
this.handleChange(this.value);
|
this.handleChange(this.value);
|
||||||
|
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.value.toString(), true);
|
||||||
},
|
},
|
||||||
handleCheckChange() {
|
handleCheckChange() {
|
||||||
const emitEvent = {
|
const emitEvent = {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import listCard from "./list-card";
|
import listCard from "./list-card";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
|
import { GaActions } from "@/constants/analytics";
|
||||||
|
|
||||||
describe("list-card.vue", () => {
|
describe("list-card.vue", () => {
|
||||||
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
||||||
|
|
@ -292,8 +293,16 @@ describe("list-card.vue", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should run handleChange if triggerButton is triggered", async () => {
|
it("Should run handleChange if triggerButton is triggered", async () => {
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listCard, {
|
const wrapper = shallowMount(listCard, {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
'$route': { query: { fmgPage: 'page-name' } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
}
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
selectingInitiatesLoad: false,
|
selectingInitiatesLoad: false,
|
||||||
},
|
},
|
||||||
|
|
@ -312,6 +321,13 @@ describe("list-card.vue", () => {
|
||||||
it("Should run handleCheckChange and displayLoader if triggerButton is triggered and seletingInitiatesLoad is true", async () => {
|
it("Should run handleCheckChange and displayLoader if triggerButton is triggered and seletingInitiatesLoad is true", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(listCard, {
|
const wrapper = shallowMount(listCard, {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
'$route': { query: { fmgPage: 'page-name' } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
}
|
||||||
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
selectingInitiatesLoad: true,
|
selectingInitiatesLoad: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useField } from "vee-validate";
|
import { useField } from "vee-validate";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "listCard",
|
name: "listCard",
|
||||||
|
|
@ -98,6 +99,10 @@ export default {
|
||||||
: this.selectedValues[0];
|
: this.selectedValues[0];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
unmounted() { // needed to clear this button's selectedValues if it is removed
|
||||||
|
this.checkValue = false;
|
||||||
|
this.handleCheckChange();
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getLabelClasses() {
|
getLabelClasses() {
|
||||||
if (this.isWide) {
|
if (this.isWide) {
|
||||||
|
|
@ -133,6 +138,7 @@ export default {
|
||||||
this.handleCheckChange();
|
this.handleCheckChange();
|
||||||
}
|
}
|
||||||
this.handleChange(this.value);
|
this.handleChange(this.value);
|
||||||
|
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.value.toString(), true);
|
||||||
},
|
},
|
||||||
handleCheckChange() {
|
handleCheckChange() {
|
||||||
const emitEvent = {
|
const emitEvent = {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue