Merge branch 'develop' into feature/CSR-108
This commit is contained in:
commit
f47af0e2fc
11 changed files with 78 additions and 1567 deletions
|
|
@ -11,17 +11,9 @@ module.exports = {
|
|||
"!src/constants/*.js",
|
||||
"!src/router/**/*.js",
|
||||
"!src/helpers/unit-test-helper.js",
|
||||
"!src/layouts/component-test/component-test.vue",
|
||||
"!src/layouts/form-test/form-test.vue",
|
||||
"!src/layouts/vin-lookup/vin-lookup.vue",
|
||||
"!src/layouts/vehicle-damage/windshield-damage-type-question/windshield-damage-type-question.vue",
|
||||
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
||||
"!src/layouts/part-questions/**/*.vue",
|
||||
"!src/layouts/reveal/**/*.vue",
|
||||
"!src/layouts/estimate/**/*.vue",
|
||||
// TODO REMOVE THESE AFTER WRITING UNIT TESTS
|
||||
"!src/ux-components/alert/alert.vue",
|
||||
"!src/helpers/validation-rules.js",
|
||||
"!src/layouts/reveal/**/*.vue"
|
||||
// END
|
||||
], // ! means exclude from coverage.
|
||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export function getDamageString() {
|
|||
if (damageLocations.length > 1) {
|
||||
returnString = "match"
|
||||
} else {
|
||||
switch(damageLocations[0]?.location) {
|
||||
switch(damageLocations[0]?.glassLocation) {
|
||||
case "Windshield":
|
||||
returnString = "windshield"
|
||||
break;
|
||||
|
|
@ -36,7 +36,7 @@ export function getDamageString() {
|
|||
|
||||
export function getIsWindshieldOnly () {
|
||||
const damageLocations = store.getters.damage.glassToReplace;
|
||||
const returnString = damageLocations.length === 1 && damageLocations[0]?.location === "Windshield" ? "windshield" : "glass";
|
||||
const returnString = damageLocations.length === 1 && damageLocations[0]?.glassLocation === "Windshield" ? "windshield" : "glass";
|
||||
return returnString;
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ export async function isGlassAvailableForCarId(carId){
|
|||
}
|
||||
|
||||
for(const option of currentGlassOptions){
|
||||
if(!newGlassOptions.data[optionsMap[option.location]].availableReplacementOptions.includes(option.name)){
|
||||
if(!newGlassOptions.data[optionsMap[option.glassLocation]].availableReplacementOptions.includes(option.glassName)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
|||
it("Should return match when multiple selected damage options are in the store", () => {
|
||||
|
||||
// Arrange / Act
|
||||
store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}, {location: "Passenger", name: "sideWindow"}];
|
||||
store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}, {glassLocation: "Passenger", glassName: "sideWindow"}];
|
||||
|
||||
const damage = getDamageString();
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
|||
it("Should return windshield when Windshield is the only selected damage option in the store", () => {
|
||||
|
||||
// Arrange / Act
|
||||
store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}];
|
||||
store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}];
|
||||
|
||||
const damage = getDamageString();
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
|||
it("Should return side window when Driver or Passenger is the only selected damage option in the store", () => {
|
||||
|
||||
// Arrange / Act
|
||||
store.getters.damage.glassToReplace = [{location: "Passenger", name: "sideWindow"}];
|
||||
store.getters.damage.glassToReplace = [{glassLocation: "Passenger", glassName: "sideWindow"}];
|
||||
|
||||
const damage = getDamageString();
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
|||
it("Should return rear window when Rear is the only selected damage option in the store", () => {
|
||||
|
||||
// Arrange / Act
|
||||
store.getters.damage.glassToReplace = [{location: "Rear", name: "rear"}];
|
||||
store.getters.damage.glassToReplace = [{glassLocation: "Rear", glassName: "rear"}];
|
||||
|
||||
const damage = getDamageString();
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
|||
describe("damage-helper.js", () => {
|
||||
it("Should return true if no mismatches between each array exist", async () => {
|
||||
// Arrange
|
||||
store.getters.damage.glassToReplace = [{location: "Windshield", name: "windshield"}];
|
||||
store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "windshield"}];
|
||||
|
||||
// Act
|
||||
const isGlassAvailable = await isGlassAvailableForCarId();
|
||||
|
|
@ -80,7 +80,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
|||
describe("damage-helper.js", () => {
|
||||
it("Should return false if any mismatches between each array exist", async () => {
|
||||
// Arrange
|
||||
store.getters.damage.glassToReplace = [{location: "Windshield", name: "sideWindow"}];
|
||||
store.getters.damage.glassToReplace = [{glassLocation: "Windshield", glassName: "sideWindow"}];
|
||||
|
||||
const isGlassAvailable = await isGlassAvailableForCarId();
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -52,6 +52,7 @@ import { required } from "@/helpers/validation-rules";
|
|||
import { errorMessages } from "@/constants/error-messages";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import store from "@/store";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
import { vinLookupMethodSelections } from "@/constants/vin-lookup-method-selections.js";
|
||||
// Define Validation Rules
|
||||
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
|
@ -94,21 +95,22 @@ export default {
|
|||
);
|
||||
},
|
||||
forwardButtonAction() {
|
||||
if (this.selectedValues[0]===vinLookupMethodSelections.MANUALVIN) {
|
||||
if (this.selectedValues[0] === vinLookupMethodSelections.MANUALVIN) {
|
||||
store.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.SELECTED_MANUAL_VIN,
|
||||
this.$route
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (this.selectedValues[0]===vinLookupMethodSelections.LICENSEPLATE) {
|
||||
if (this.selectedValues[0] === vinLookupMethodSelections.LICENSEPLATE) {
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.SELECTED_LICENSE_PLATE,
|
||||
this.$route
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (this.selectedValues[0]===vinLookupMethodSelections.HOMEADDRESS) {
|
||||
if (this.selectedValues[0] === vinLookupMethodSelections.HOMEADDRESS) {
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.SELECTED_HOME_ADDRESS,
|
||||
this.$route
|
||||
|
|
|
|||
|
|
@ -1,244 +0,0 @@
|
|||
<template>
|
||||
<div class="container-fluid shadow rounded-3 p-2 position-relative make-tall">
|
||||
<funnelHeader ref="funnelHeader" />
|
||||
<vehicleBanner ref="vehicleBanner" :displayGenericVehicleImage=false />
|
||||
<funnelSubHeader ref="funnelSubHeader" />
|
||||
<Form
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit"
|
||||
ref="theForm"
|
||||
v-slot="{ values, meta, errors }"
|
||||
>
|
||||
<damageLocationQuestion
|
||||
ref="damageLocation"
|
||||
v-model="selectedDamageLocations"
|
||||
groupName="DamageLocationQuestion"
|
||||
/>
|
||||
<windshieldOptions
|
||||
ref="windshieldOptions"
|
||||
v-model="selectedWindshieldOptions"
|
||||
:hasRepairReplaceConflict="hasRepairReplaceConflict"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<alert
|
||||
class="my-3"
|
||||
v-show="hasRepairReplaceConflict"
|
||||
alertClass="alert-danger"
|
||||
alertHeadline="You'll need to schedule separate appointments"
|
||||
alertCopy="Vehicle service requiring both glass repair and replacement must be scheduled separately, as they're performed by different technicians. Continue scheduling your first service now, and then come back to schedule the second service."
|
||||
:isDismissible="false"
|
||||
/>
|
||||
<sideDoorOptions
|
||||
ref="sideDoorOptions"
|
||||
groupName="SideDoorSideQuestion"
|
||||
v-model="sideDoorOptionsData"
|
||||
v-show="!hasRepairReplaceConflict"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="backGlassOptions"
|
||||
:isAvailable="isRearWindowDamageLocation && !hasRepairReplaceConflict"
|
||||
v-model="selectedRearReplaceOptions"
|
||||
groupName="BackGlassReplaceOptionsQuestion"
|
||||
validationRules="replace-options-required"
|
||||
/>
|
||||
<funnel-footer
|
||||
ref="funnelFooter"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@back-clicked="backButtonAction"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
/>
|
||||
|
||||
<!-- KEEP TEMPORARILY FOR TROUBLESHOOTING VALIDATION -->
|
||||
<div class="g-2 mt-6 mx-4 w-25 position-fixed fixed-top">
|
||||
<p>Current Form, values:</p>
|
||||
<pre>{{ values }}</pre>
|
||||
<p>Errors:</p>
|
||||
<pre>{{ errors }}</pre>
|
||||
<p>Is Form Valid? (Meta.valid):</p>
|
||||
<pre>{{ meta.valid }}</pre>
|
||||
</div>
|
||||
|
||||
</Form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Components
|
||||
import funnelHeader from "@/common-components/funnel-header/funnel-header";
|
||||
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
|
||||
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
||||
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
|
||||
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
||||
import damageLocationQuestion from "@/layouts/vehicle-damage/damage-location-question/damage-location-question";
|
||||
import sideDoorOptions from "@/layouts/vehicle-damage/side-door-options/side-door-options";
|
||||
import windshieldOptions from "@/layouts/vehicle-damage/windshield-options/windshield-options";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
|
||||
// Supporting files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import store from "@/store";
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED));
|
||||
|
||||
export default {
|
||||
name: "form-test",
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage('vehicle-damage');
|
||||
const damageOptionsPromise =
|
||||
baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.GET_DAMAGE_OPTIONS,
|
||||
{ carId: store.getters.vehicle.carId }
|
||||
);
|
||||
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
},
|
||||
{
|
||||
resultKey: "damageOptions",
|
||||
promise: damageOptionsPromise,
|
||||
},
|
||||
];
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
// Call the "next" function to complete the transition to this page.
|
||||
next((vm) => {
|
||||
vm.$refs.funnelHeader.initializeComponent(
|
||||
resultMap.cmsContent.FunnelHeaderWidget
|
||||
);
|
||||
vm.$refs.vehicleBanner.initializeComponent(
|
||||
resultMap.cmsContent.VehicleBannerWidget
|
||||
);
|
||||
vm.$refs.funnelSubHeader.initializeComponent(
|
||||
resultMap.cmsContent.FunnelSubHeaderWidget
|
||||
);
|
||||
vm.$refs.damageLocation.initializeComponent(
|
||||
resultMap.cmsContent.DamageLocationQuestion, resultMap.damageOptions
|
||||
);
|
||||
vm.$refs.sideDoorOptions.initializeComponent(
|
||||
resultMap.cmsContent.SideDoorSideQuestion, resultMap.cmsContent.DriverSideReplaceOptionsQuestion, resultMap.cmsContent.PassengerSideReplaceOptionsQuestion, resultMap.damageOptions.driverSideOptions.availableReplacementOptions, resultMap.damageOptions.passengerSideOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.windshieldOptions.initializeComponent(
|
||||
resultMap.cmsContent.WindshieldDamageTypeQuestion, resultMap.cmsContent.WindshieldChipCountQuestion,
|
||||
resultMap.cmsContent.WindshieldReplaceOptionsQuestion, resultMap.damageOptions.windshieldOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.backGlassOptions.initializeComponent(
|
||||
resultMap.cmsContent.RearReplaceOptionsQuestion, resultMap.damageOptions.backGlassOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.funnelFooter.initializeComponent(
|
||||
resultMap.cmsContent.FunnelFooterWidget
|
||||
);
|
||||
});
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
selectedDamageLocations: [],
|
||||
sideDoorOptionsData: {
|
||||
selectedDoorSides: [],
|
||||
selectedDriverSideReplaceOptions: [],
|
||||
selectedPassengerSideReplaceOptions: []
|
||||
},
|
||||
selectedWindshieldOptions: [],
|
||||
selectedRearReplaceOptions: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
return store.getters.vehicle.carId !== null;
|
||||
},
|
||||
resetDependentState() {
|
||||
store.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
||||
},
|
||||
onSubmit(values) {
|
||||
window.alert('Success! Submitted values: ' + JSON.stringify(values, null ,2))
|
||||
console.log('submitted: ', JSON.stringify(values, null ,2));
|
||||
},
|
||||
onInvalidSubmit({ values, errors, results }) {
|
||||
// identify the first error field and put focus on it
|
||||
console.log("values: ", values);
|
||||
console.log("errors: ", errors);
|
||||
console.log("results: ", results);
|
||||
// get error names array
|
||||
const errorNames = errors ? Object.keys(errors) : [];
|
||||
const firstErrorEl = errorNames[0];
|
||||
if (firstErrorEl) {
|
||||
console.log('firstErrorEl: ', firstErrorEl);
|
||||
const qsString = "[data-focus-target='" + firstErrorEl + "']";
|
||||
document.querySelector(qsString).focus();
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isWindshieldDamageLocation() {
|
||||
return this.selectedDamageLocations.some(selectedDamages =>
|
||||
{
|
||||
return selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD;
|
||||
});
|
||||
},
|
||||
isSideDoorDamageLocation() {
|
||||
return this.selectedDamageLocations.some(selectedDamages =>
|
||||
{
|
||||
return selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR;
|
||||
});
|
||||
},
|
||||
isRearWindowDamageLocation() {
|
||||
return this.selectedDamageLocations.some(selectedDamages =>
|
||||
{
|
||||
return selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW;
|
||||
});
|
||||
},
|
||||
isWindshieldRepair() {
|
||||
if (!this.isWindshieldDamageLocation) return false;
|
||||
|
||||
return this.selectedWindshieldOptions.selectedWindshieldDamageType && this.selectedWindshieldOptions.selectedWindshieldDamageType.some(selectedDamageType =>
|
||||
{
|
||||
return selectedDamageType.toUpperCase() === "REPAIR";
|
||||
});
|
||||
},
|
||||
isDriverSideReplace() {
|
||||
if (!this.isSideDoorDamageLocation) return false;
|
||||
|
||||
return this.sideDoorOptionsData.selectedDoorSides.some(selectedDriverSide =>
|
||||
{
|
||||
return selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE;
|
||||
});
|
||||
},
|
||||
isPassengerSideReplace() {
|
||||
if (!this.isSideDoorDamageLocation) return false;
|
||||
|
||||
return this.sideDoorOptionsData.selectedDoorSides.some(selectedPassengerSide =>
|
||||
{
|
||||
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
|
||||
});
|
||||
},
|
||||
hasRepairReplaceConflict() {
|
||||
return this.isWindshieldDamageLocation && this.selectedDamageLocations.length > 1 && this.isWindshieldRepair;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
funnelHeader,
|
||||
funnelFooter,
|
||||
vehicleBanner,
|
||||
funnelSubHeader,
|
||||
sideDoorOptions,
|
||||
damageLocationQuestion,
|
||||
windshieldOptions,
|
||||
replaceOptionsQuestion,
|
||||
Form,
|
||||
alert,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -267,8 +267,7 @@ export default {
|
|||
`Continue with ${vinLookup.data.vehicle.year} ${vinLookup.data.vehicle.make} ${vinLookup.data.vehicle.model}`
|
||||
);
|
||||
this.isVinValid = true;
|
||||
this.isSelectedGlassAvailableForVehicle =
|
||||
await isGlassAvailableForCarId(vinLookup.data.vehicle.carId);
|
||||
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vinLookup.data.vehicle.carId);
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ describe("vehicle-damage.vue", () => {
|
|||
|
||||
wrapper.vm.selectedRearReplaceOptions = ["Stationary"];
|
||||
|
||||
const expectedGlassToReplace = [{ location: "Windshield", name: "Single" }, { location: "Driver", name: "Back" },
|
||||
{ location: "Passenger", name: "Quarter" }, { location: "Rear", name: "Stationary" }];
|
||||
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" },
|
||||
{ glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }];
|
||||
|
||||
//Act
|
||||
vehicleDamage.beforeRouteEnter.call(
|
||||
|
|
@ -237,7 +237,7 @@ describe("vehicle-damage.vue", () => {
|
|||
selectedWindshieldDamageType: ["Replace"]
|
||||
};
|
||||
|
||||
const expectedGlassToReplace = [{ location: "Windshield", name: "Single" },];
|
||||
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" },];
|
||||
|
||||
//Act
|
||||
vehicleDamage.beforeRouteEnter.call(
|
||||
|
|
|
|||
|
|
@ -314,25 +314,25 @@ export default {
|
|||
const selectedGlassToReplace = [];
|
||||
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair){
|
||||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(wsItem => {
|
||||
selectedGlassToReplace.push({ location: damageLocationsSelected.WINDSHIELD, name: wsItem});
|
||||
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.WINDSHIELD, glassName: wsItem});
|
||||
})
|
||||
}
|
||||
|
||||
if (this.isDriverSideReplace){
|
||||
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach(driverItem => {
|
||||
selectedGlassToReplace.push({ location: damageLocationsSelected.DRIVER, name: driverItem});
|
||||
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.DRIVER, glassName: driverItem});
|
||||
})
|
||||
}
|
||||
|
||||
if (this.isPassengerSideReplace){
|
||||
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(passengerItem => {
|
||||
selectedGlassToReplace.push({ location: damageLocationsSelected.PASSENGER, name: passengerItem});
|
||||
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.PASSENGER, glassName: passengerItem});
|
||||
})
|
||||
}
|
||||
|
||||
if (this.isRearWindowDamageLocation) {
|
||||
this.selectedRearReplaceOptions.forEach(rearItem => {
|
||||
selectedGlassToReplace.push({ location: damageLocationsSelected.REAR, name: rearItem});
|
||||
selectedGlassToReplace.push({ glassLocation: damageLocationsSelected.REAR, glassName: rearItem});
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,11 +23,9 @@
|
|||
isRequired
|
||||
disableAutoFill
|
||||
validationRules="vin-required|vin-format"
|
||||
:isDisabled="isVinFieldReadOnly"
|
||||
:isDisabled="vinPopulatedOnPageLoad"
|
||||
maxLength="17"
|
||||
:mask="vinMask"
|
||||
@focus="setVinTouched"
|
||||
@maska="rawVinValue = $event.target.dataset.maskRawValue"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -70,10 +68,10 @@
|
|||
/>
|
||||
<alert
|
||||
class="my-4"
|
||||
:manualHeadline="PerfectMatchNewVinAlertReadOnlyHeader"
|
||||
:manualCopy="PerfectMatchNewVinAlertReadOnlyBody"
|
||||
:manualHeadline="PerfectMatchInsuranceVerifiedAlertHeader"
|
||||
:manualCopy="PerfectMatchInsuranceVerifiedAlertBody"
|
||||
v-model="customAlertData"
|
||||
v-if="isVinFieldReadOnly"
|
||||
v-if="vinPopulatedOnPageLoad && isInsuranceVerified"
|
||||
alertClass="alert-success"
|
||||
/>
|
||||
<alert
|
||||
|
|
@ -101,10 +99,10 @@
|
|||
/>
|
||||
<alert
|
||||
class="my-4"
|
||||
:manualHeadline="PerfectMatchNewVinAlertHeader"
|
||||
:manualCopy="PerfectMatchNewVinAlertBody"
|
||||
:manualHeadline="PerfectMatchInsuranceNotVerifiedAlertHeader"
|
||||
:manualCopy="PerfectMatchInsuranceNotVerifiedAlertBody"
|
||||
v-model="customAlertData"
|
||||
v-if="perfectMatchNewVinAlert && !noServiceZip && !vinNotFound && meta.valid && !isVinFieldReadOnly"
|
||||
v-if="vinPopulatedOnPageLoad && !isInsuranceVerified"
|
||||
alertClass="alert-success"
|
||||
/>
|
||||
<funnelFooter
|
||||
|
|
@ -140,10 +138,8 @@ import { errorMessages } from "@/constants/error-messages";
|
|||
import { getDamageString, getIsWindshieldOnly, isGlassAvailableForCarId } from "@/helpers/damage-helper";
|
||||
import { required, regex } from "@/helpers/validation-rules";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import { navigateAfterSaveToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||
import { StatusCodes } from 'http-status-codes';
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
|
||||
|
|
@ -187,15 +183,14 @@ export default {
|
|||
previouslyEnteredCarId: '',
|
||||
invalidZip: '',
|
||||
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
|
||||
initialVin: this.getVinFromStore(),
|
||||
vinTouched: false,
|
||||
rawVinValue: "",
|
||||
isInsuranceVerified: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.attachCustomEvents();
|
||||
if (this.vinPopulatedOnPageLoad) {
|
||||
this.setupVinMask();
|
||||
this.setupVinMask();
|
||||
this.isInsuranceVerified = store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -210,12 +205,6 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
perfectMatchNewVinAlert() {
|
||||
const vinToCheck = this.vinTouched ? this.rawVinValue : this.initialVin;
|
||||
const isVinPerfectMatch = this.vinPopulatedOnPageLoad && vinToCheck === this.getVinFromStore();
|
||||
this.updateIsCarIdDifferent(isVinPerfectMatch);
|
||||
return isVinPerfectMatch;
|
||||
},
|
||||
MatchedDifferentVehicleAlertHeader(){
|
||||
const text = this.getCmsContent("MatchedDifferentVehicle",
|
||||
"HeadlineText").replaceAll("{custom:damage}", getDamageString());
|
||||
|
|
@ -231,41 +220,29 @@ export default {
|
|||
},
|
||||
NoServiceZipHeader(){
|
||||
const text = this.getCmsContent("NoServiceZipWidget", "HeadlineText").replaceAll("{custom:serviceZip}", this.invalidZip);
|
||||
|
||||
return text;
|
||||
},
|
||||
NoServiceZipBody(){
|
||||
return this.getCmsContent("NoServiceZipWidget", "BodyText");
|
||||
},
|
||||
PerfectMatchNewVinAlertHeader() {
|
||||
return this.getCmsContent("PerfectMatchNewVinAlert", "HeadlineText");
|
||||
PerfectMatchInsuranceNotVerifiedAlertHeader() {
|
||||
return this.getCmsContent("PerfectMatchInsuranceNotVerifiedAlert", "HeadlineText");
|
||||
},
|
||||
PerfectMatchNewVinAlertBody() {
|
||||
return this.getCmsContent("PerfectMatchNewVinAlert", "BodyText").replaceAll("{custom:damage}",
|
||||
PerfectMatchInsuranceNotVerifiedAlertBody() {
|
||||
return this.getCmsContent("PerfectMatchInsuranceNotVerifiedAlert", "BodyText").replaceAll("{custom:damage}",
|
||||
getDamageString())
|
||||
},
|
||||
PerfectMatchNewVinAlertReadOnlyHeader () {
|
||||
return this.getCmsContent("PerfectMatchNewVinAlertReadOnly", "HeadlineText");
|
||||
PerfectMatchInsuranceVerifiedAlertHeader () {
|
||||
return this.getCmsContent("PerfectMatchInsuranceVerifiedAlert", "HeadlineText");
|
||||
},
|
||||
PerfectMatchNewVinAlertReadOnlyBody () {
|
||||
return this.getCmsContent("PerfectMatchNewVinAlertReadOnly", "BodyText").replaceAll("{custom:damage}",
|
||||
PerfectMatchInsuranceVerifiedAlertBody () {
|
||||
return this.getCmsContent("PerfectMatchInsuranceVerifiedAlert", "BodyText").replaceAll("{custom:damage}",
|
||||
getIsWindshieldOnly())
|
||||
},
|
||||
isVinFieldReadOnly(){
|
||||
return this.$store.getters.payment.insuranceCoverage.isVerified || getFunnelCookie().HasDelayedClaimRegistration;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setVinTouched() {
|
||||
if (!this.vinTouched) {
|
||||
this.vinMask = "XXXXXXXXXXXXXXXXX";
|
||||
this.vin = this.initialVin;
|
||||
}
|
||||
|
||||
this.vinTouched = true;
|
||||
},
|
||||
setupVinMask() {
|
||||
const lastSixChars = this.initialVin.substring(11, this.initialVin.length);
|
||||
const lastSixChars = this.vin.substring(11, this.vin.length);
|
||||
this.vinMask = `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
|
||||
},
|
||||
arePagePrerequisitesValid() {
|
||||
|
|
@ -315,17 +292,16 @@ export default {
|
|||
let vehicleLookupResponse;
|
||||
|
||||
const zipValidation = this.validateZip(this.zip);
|
||||
|
||||
if (this.vinTouched && this.vin != this.initialVin) {
|
||||
// If the user has clicked on the VIN field, either they are doing a new VIN lookup or changing the VIN previously matched.
|
||||
// Therefore we need to do a Vehicle Lookup
|
||||
const vinToLookup = this.vinTouched ? this.vin : this.initialVin;
|
||||
const vehicleLookup = this.lookupVehicle(vinToLookup);
|
||||
|
||||
|
||||
// If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation
|
||||
if (!this.vinPopulatedOnPageLoad) {
|
||||
// Perform Zip Validation
|
||||
zipValidationResponse = await zipValidation;
|
||||
|
||||
// Perform Vehicle Lookup
|
||||
const vehicleLookup = this.lookupVehicle(this.vin);
|
||||
vehicleLookupResponse = await vehicleLookup.catch(() => {
|
||||
this.vinNotFound = true;
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
return false;
|
||||
});
|
||||
|
||||
|
|
@ -335,44 +311,46 @@ export default {
|
|||
}
|
||||
|
||||
if (!vehicleLookupResponse || !zipValidationResponse.data.isServiceable) {
|
||||
// If either lookup fails, remove the loader and stop processing the page.
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
return;
|
||||
}
|
||||
|
||||
this.isCarIdDifferent = vehicleLookupResponse.data.carId !== store.getters.vehicle.carId;
|
||||
|
||||
if (this.isCarIdDifferent && (vehicleLookupResponse.data.carId !== this.previouslyEnteredCarId)) {
|
||||
this.previouslyEnteredCarId = vehicleLookupResponse.data.carId;
|
||||
this.noServiceZip = false;
|
||||
this.customAlertData.vehicleInfo = vehicleLookupResponse.data;
|
||||
this.$refs.funnelFooter.updateButtonText(`Continue with ${vehicleLookupResponse.data.year} ${vehicleLookupResponse.data.make} ${vehicleLookupResponse.data.model}`);
|
||||
this.isVinValid = true;
|
||||
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vehicleLookupResponse.data.carId);
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
this.isCarIdDifferent = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateStore(vehicleLookupResponse.data, zipValidationResponse.data);
|
||||
this.navigateForward();
|
||||
|
||||
} else {
|
||||
// If a VIN has already been found. Validate the Service Zip (in case of changes)
|
||||
const zipValidationResponse = await zipValidation;
|
||||
|
||||
// Check if Service Zip entered is serviceable, if not display an alert
|
||||
if (!zipValidationResponse.data.isServiceable) {
|
||||
// Check if Service Zip entered is serviceable
|
||||
if (zipValidationResponse.data.isServiceable) {
|
||||
// If the Service Zip entered is serviceable then save the Zip Info and Email Address and navigate forward
|
||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_ZIP_CODE, this.zip);
|
||||
store.commit(storeMutations.UPDATE_SERVICE_LOCATION_STATE, zipValidationResponse.data.state);
|
||||
store.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, this.email);
|
||||
this.navigateForward();
|
||||
} else {
|
||||
// If the Service Zip is NOT serviceable then show an alert
|
||||
this.setupUiForNonServiceableZip(this.zip);
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
return;
|
||||
} else {
|
||||
this.navigateForward();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vehicleLookupResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isCarIdDifferent = vehicleLookupResponse.data.carId !== store.getters.vehicle.carId;
|
||||
|
||||
if (this.isCarIdDifferent && (vehicleLookupResponse.data.carId !== this.previouslyEnteredCarId)) {
|
||||
this.previouslyEnteredCarId = vehicleLookupResponse.data.carId;
|
||||
this.noServiceZip = false;
|
||||
this.customAlertData.vehicleInfo = vehicleLookupResponse.data;
|
||||
this.$refs.funnelFooter.updateButtonText(`Continue with ${vehicleLookupResponse.data.year} ${vehicleLookupResponse.data.make} ${vehicleLookupResponse.data.model}`);
|
||||
this.isVinValid = true;
|
||||
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vehicleLookupResponse.data.carId);
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
this.isCarIdDifferent = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateStore(vehicleLookupResponse.data, zipValidationResponse.data);
|
||||
this.navigateForward();
|
||||
|
||||
},
|
||||
navigateForward(){
|
||||
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
|
||||
|
|
|
|||
|
|
@ -18,22 +18,7 @@ import eventBus from "@/helpers/event-bus/event-bus";
|
|||
import store from "@/store";
|
||||
import analyticsMixin from "@/mixins/analytics-mixin";
|
||||
|
||||
// Components
|
||||
import ComponentTest from "@/layouts/component-test/component-test.vue";
|
||||
import FormTest from "@/layouts/form-test/form-test.vue";
|
||||
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: "/component-test", // This is a temporary route for testing.
|
||||
name: "ComponentTest",
|
||||
component: ComponentTest,
|
||||
},
|
||||
{
|
||||
path: "/form-test", // This is a temporary route for testing.
|
||||
name: "FormTest",
|
||||
component: FormTest,
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
name: "root",
|
||||
|
|
|
|||
Loading…
Reference in a new issue