Merge branch 'develop' into feature/digital/SSR-346

# Conflicts:
#	src/layouts/coverage-statement/coverage-statement.vue
#	src/styles/common-styles.scss
This commit is contained in:
Jason Wheeler 2023-04-11 12:13:26 -04:00
commit 92f4da0852
32 changed files with 2410 additions and 2257 deletions

View file

@ -2,22 +2,6 @@ import { shallowMount } from "@vue/test-utils";
import buttonQuestion from "@/digital-components/button-question/button-question";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
describe("buttonQuestion.vue", () => {
it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => {
// Act
const wrapper = shallowMount(buttonQuestion, {
propsData: {
isOverflowScrollable: true,
groupName: "group-name",
},
});
// Assert
const fieldSet = wrapper.find("fieldset");
expect(fieldSet.classes()).toContain("overflow-scroll");
});
});
describe("buttonQuestion.vue", () => {
it("Fieldset classes should contain row if button type is listCard", () => {
// Act

View file

@ -4,15 +4,15 @@
:class="
isOverflowScrollable ? 'button-question button-question-overflow' : 'button-question'
">
<div v-if="questionText && answers && answers.length > 0" class="question-text d-flex px-5">
<div v-if="questionText && answers && answers.length > 0" class="question-text d-flex"
:class="{'small-question-text': isSmallQuestionText,'small-question-label-text':isSmallQuestionLabelText}">
<span class="fw-bold w-100">{{ questionText }}</span>
</div>
<div class="w-100 d-flex justify-content-center">
<fieldset
class="w-100 px-5"
class="w-100"
:aria-required="isRequired"
:class="getFieldSetClasses"
:role="isMultiSelect ? 'group' : 'radiogroup'"
:aria-labelledby="formatString(groupName)">
<legend
@ -67,7 +67,7 @@
</div>
</fieldset>
</div>
<div class="row form-test-error mt-1 px-5">
<div class="row form-test-error mt-1">
<error-message
:name="formatString(groupName)"
v-if="!suppressError"></error-message>
@ -121,6 +121,8 @@ export default {
useTextForValue: Boolean,
valueToLogType: String,
additionalButtonStyling: String,
isSmallQuestionText: Boolean,
isSmallQuestionLabelText: Boolean,
},
beforeMount() {
if (this.buttonTypeObject) {
@ -134,13 +136,20 @@ export default {
},
computed: {
getFieldSetClasses() {
if (this.isOverflowScrollable) {
return "container-fluid overflow-scroll position-absolute pt-1 py-0";
} else if (this.buttonTypeString == "listCard") {
return "w-100";
} else {
return "";
}
const baseClasses = this.isOverflowScrollable
? "container-fluid overflow-scroll position-absolute px-5 pt-1 py-0"
: this.buttonTypeString == "listCard"
? "w-100"
: "";
const SmallQuestionTextClass = this.isSmallQuestionText
? baseClasses + "small-question-text"
: baseClasses;
const SmallQuestionLabelText = this.isSmallQuestionLabelText
? SmallQuestionTextClass + "small-question-label-text"
: SmallQuestionTextClass;
return SmallQuestionLabelText;
},
getComponentLoopWrapperClasses() {
let classes;
@ -224,16 +233,6 @@ export default {
</script>
<style lang="scss">
.button-question-overflow {
height: calc(100vh - 274px);
.overflow-scroll {
// Height will be determined by overall height of content above list
height: calc(100% - 400px);
overflow-x: hidden !important;
-webkit-overflow-scrolling: touch;
}
}
.button-question {
color: $black;
@ -254,35 +253,35 @@ export default {
}
}
.vehicle-parts {
.question-text {
.small-question-text {
&.question-text {
span {
font-size: 0.875rem;
text-align: left;
margin: 0 0 0.5rem 0;
}
}
.question-text {
&.question-text {
margin: 0;
}
fieldset {
&fieldset {
.ui-radio {
margin: 0;
}
}
}
.welcome {
.question-text {
span {
.small-question-label-text {
&.question-text {
span {
text-align: left;
margin: 0 0 0.25rem 0;
}
}
.question-text {
&.question-text {
margin: 0;
}
fieldset {
&fieldset {
.ui-radio {
margin: 0;
}

View file

@ -1,5 +1,5 @@
<template>
<div v-for="(q, i) in questions" :key="i">
<div v-for="(q, i) in questions" :key="i" class="questionBlock" >
<transition appear name="fade" mode="out-in">
<buttonQuestion
v-if="q.answerSelected || q.questionSequence === currentQuestionNum"
@ -161,3 +161,12 @@ export default {
},
};
</script>
<style lang="scss">
.questionBlock:not(:nth-of-type(1)){
.button-question.radioQuestion >div {
margin-top: 0.73rem;
}
}
</style>

View file

@ -10,7 +10,7 @@
<alert
ref="alertNoMatchWarning"
v-if="displayNoMatchWarning"
class="mb-4"
class="mb-4 mt-4"
cmsWidgetName="AlertNoMatchWarningWidget"
alertClass="alert-warning"
v-bind:isDismissible="false" />

View file

@ -1,34 +1,43 @@
<template>
<div :class="`page-container-grouped-styles questions-page`">
<loadingModal ref="loadingModal" />
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="fade-on-route-transition sub-container overflow-scroll">
<vehicleBanner class="mb-3" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<alert
ref="alertFewMoreQuestions"
cmsWidgetName="alertWidget"
class="m-5"
alertClass="alert-warning"
:manualHeadline="alertFewMoreQuestionsHeader"
:manualCopy="alertFewMoreQuestionsCopy"
v-bind:isDismissible="false" />
<div v-for="(questionsDatum, i) in questionsData" :key="questionsDatum.key">
<questionChain
ref="questionChain"
v-model="selectedAnswers[questionsDatum.answerKey]"
:questionData="questionsDatum.questions"
:index="i"
v-if="showThisQuestionChain(questionsDatum, i)"
:answerKey="questionsDatum.answerKey"
:validationRules="validationRules" />
<div class="fade-on-route-transition position-relative">
<loadingModal ref="loadingModal" />
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<vehicleBanner class="mb-3" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<alert
ref="alertFewMoreQuestions"
cmsWidgetName="alertWidget"
alertClass="alert-warning"
:manualHeadline="alertFewMoreQuestionsHeader"
:manualCopy="alertFewMoreQuestionsCopy"
v-bind:isDismissible="false" />
<div v-for="(questionsDatum, i) in questionsData" :key="questionsDatum.key">
<questionChain
ref="questionChain"
v-model="selectedAnswers[questionsDatum.answerKey]"
:questionData="questionsDatum.questions"
:index="i"
v-if="showThisQuestionChain(questionsDatum, i)"
:answerKey="questionsDatum.answerKey"
:validationRules="validationRules" />
</div>
<siteFooter
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!isMetaValid"
@back-clicked="handleBackButtonAction"
@ForwardClicked="handleForwardButtonAction" />
</div>
</div>
</div>
</div>
</div>
<siteFooter
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!isMetaValid"
@back-clicked="handleBackButtonAction"
@ForwardClicked="handleForwardButtonAction" />
</div>
</div>
</template>
@ -95,10 +104,6 @@ export default {
</script>
<style lang="scss">
.overflow-scroll {
height: calc(100% - 180px);
overflow-x: hidden !important;
}
.questions-page {
.question-text {
margin-bottom: 0.5rem;

View file

@ -7,20 +7,7 @@
</button>
</div>
<!-- Modal -->
<div class="modal menu-modal fade" data-bs-backdrop="false" id="footerModal" tabindex="-1" aria-labelledby="footerModalLabel" aria-hidden="true" v-on="{ 'show.bs.modal' : show, 'hide.bs.modal' : hide }" :style="`height: calc(100% - ${currentFooterAndHeaderHeight}px);`">
<div class="menu-modal-container">
<button
class="menu-button"
type="button"
:class="[isActive ? 'active' : '']"
data-bs-toggle="modal"
data-bs-target="#footerModal"
aria-label="Hamburger Menu (modal window)">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
</button>
</div>
<div class="modal menu-modal fade" data-bs-backdrop="false" id="footerModal" tabindex="-1" aria-labelledby="footerModalLabel" aria-hidden="true" v-on="{ 'show.bs.modal' : show, 'hide.bs.modal' : hide }">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header visually-hidden">
@ -78,8 +65,8 @@ export default {
show() {
this.currentFooterAndHeaderHeight = this.getFooterInfoBoxHeight() + 72;
this.isActive = true;
document.querySelector('.page-container-grouped-styles').scrollTo({
top: 0, behavior: 'smooth'
document.querySelector('.fade-on-route-transition').scrollTo({
top: 0, behavior: 'instant'
});
},
hide() {
@ -112,7 +99,7 @@ export default {
justify-content: center;
align-items: center;
padding: 0;//Required to prevent 'squish' on iPhone
z-index: 1050;
z-index: 1060;
.bar1,
.bar2,
.bar3 {

View file

@ -0,0 +1,45 @@
import { shallowMount } from "@vue/test-utils";
import steeringTextModal from "./steering-text";
import { createApp } from 'vue';
import { createPinia } from "pinia";
import App from '@/App.vue';
describe("steering-text.vue", () => {
test("Should display steering text from CMS for state MA", async () => {
// Act
const wrapper = shallowMount(steeringTextModal, {
mixins: [mockMixin],
props: {
cmsWidgetName: "MASteeringTextWidget",
},
attachTo: document.body,
});
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"]));
});
});
const vueApp = createApp(App);
const pinia = createPinia();
vueApp.use(pinia);
///////////////
// Constants //
///////////////
const mockMixin = {
methods: {
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
return mockCmsContent[cmsFieldName];
}),
},
};
const mockCmsContent = {
BodyText: "MASteeringText",
};

View file

@ -0,0 +1,37 @@
<template>
<div>
<textBlock
cmsWidgetName="MASteeringText"
id="SteeringTextContent"
/>
<div>
<p class="small" v-if="isStateMA" v-html="MASteeringText" ></p>
</div>
</div>
</template>
<script>
import { useMainStore } from "@/store";
export default{
name: "steeringTextModal",
computed: {
MASteeringText() {
return this.getCmsContent("MASteeringText", "BodyText");
},
isStateMA()
{
if (this.mainStore.order.customer.address.state=='MA')
{
return true
}
}
},
setup() {
const mainStore = useMainStore();
return { mainStore };
}
}
</script>

View file

@ -1,60 +1,65 @@
<template>
<Form
@submit="onSubmit"
@invalid-submit="onInvalidSubmit"
ref="theForm"
v-slot="{ meta }"
autocomplete="off">
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles">
<siteHeader cmsWidgetName="SiteHeaderWidget" ref="siteHeader" />
<div class="fade-on-route-transition sub-container overflow-scroll px-5">
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
ref="vehicleBanner"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" ref="siteSubHeader" />
<alert
ref="alertVinNotFound"
v-if="displayVinNotFoundAlert"
class="mb-4"
cmsWidgetName="AlertVinNotFoundWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<alert
ref="alertMatchedDifferentVehicle"
v-if="displayMatchedDifferentVehicleAlert"
class="mb-4"
:manualHeadline="AlertMatchedDifferentVehicleHeader"
:manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
<alert
ref="alertMatchedTwoIdenticalYMMVehicle"
v-if="displayMatchedTwoIdenticalYMMVehicleAlert"
class="mb-4"
cmsWidgetName="AlertMatchedTwoIdenticalYMMVehicleWidget"
:manualHeadline="AlertMatchedTwoIdenticalYMMVehicleHeader"
:manualCopy="AlertMatchedTwoIdenticalYMMVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
<alert
ref="alertVinLookupsByHomeAddressNotAllowed"
v-if="displayVinLookupByHomeAddressNotAllowedAlert"
class="mb-4"
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
ref="vehicleBanner"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" ref="siteSubHeader" />
<alert
ref="alertVinNotFound"
v-if="displayVinNotFoundAlert"
class="mb-4 mt-4"
cmsWidgetName="AlertVinNotFoundWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<alert
ref="alertMatchedDifferentVehicle"
v-if="displayMatchedDifferentVehicleAlert"
class="mb-4 mt-4"
:manualHeadline="AlertMatchedDifferentVehicleHeader"
:manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
<alert
ref="alertMatchedTwoIdenticalYMMVehicle"
v-if="displayMatchedTwoIdenticalYMMVehicleAlert"
class="mb-4 mt-4"
cmsWidgetName="AlertMatchedTwoIdenticalYMMVehicleWidget"
:manualHeadline="AlertMatchedTwoIdenticalYMMVehicleHeader"
:manualCopy="AlertMatchedTwoIdenticalYMMVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
<alert
ref="alertVinLookupsByHomeAddressNotAllowed"
v-if="displayVinLookupByHomeAddressNotAllowedAlert"
class="mb-4 mt-4"
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
<siteFooter
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
:isDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@back-clicked="backButtonAction"
:isForwardActionDisabled="!meta.valid" />
<siteFooter
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
:isDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@back-clicked="backButtonAction"
:isForwardActionDisabled="!meta.valid" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Form>
@ -147,211 +152,203 @@ export default {
let vehicleInfoToCommit = {};
const vinLookupResponse = useMainStore().lookupVinByAddress ({
licenseLastName: this.customerQuestions.lastName,
licenseStreetAddress: this.customerQuestions.addressQuestions.streetAddress,
licenseZip: this.customerQuestions.addressQuestions.zipCode,
licenseState: this.customerQuestions.addressQuestions.state,
}
);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "vinLookupResponse",
promise: vinLookupResponse,
}
];
const resultMap = await settleAllPromises(promiseResultMap);
// If VIN Lookup by address is forbidden by State Restrictions then show an alert
if (!resultMap.vinLookupResponse.isStatePermissible) {
// State Restrictions forbid lookup by address
this.displayVinLookupByHomeAddressNotAllowedAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
licenseLastName: this.customerQuestions.lastName,
licenseStreetAddress: this.customerQuestions.addressQuestions.streetAddress,
licenseZip: this.customerQuestions.addressQuestions.zipCode,
licenseState: this.customerQuestions.addressQuestions.state,
}
);
const carsFound = resultMap.vinLookupResponse.vinVehicles;
// Handle cases for different amounts of VINS found for the address.
if (carsFound.length == 1) {
// Single VIN found
const carFound = carsFound[0].vehicle;
this.isCarIdDifferent = carFound.carId !== useMainStore().order.vehicle.carId;
if (this.isCarIdDifferent && carFound.carId !== this.previouslyEnteredCarId) {
// Display Alert
this.previouslyEnteredCarId = carFound.carId;
this.customAlertData.vehicleInfo = carFound;
if(this.isTwoIdenticalYMMVehicleFound){
this.displayMatchedTwoIdenticalYMMVehicleAlert = true;
this.forwardButtonCarStyle= carFound.style;
}
else{
this.displayMatchedDifferentVehicleAlert = true;
}
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
carFound.carId
);
// Update button "Continue with..."
this.$refs.siteFooter.updateButtonText(
`Continue with ${carFound.year} ${carFound.make} ${carFound.model} ${this.forwardButtonCarStyle}`
);
return this.$refs.siteFooter.removeLoader();
}
// update data
vehicleInfoToCommit = Object.assign(carFound, { vin: carsFound[0].vin });
} else if (carsFound.length > 1) {
// If multiple cars were found and one and only one of them matches the carId entered, save the vehicle info
const matchingCars = carsFound.filter(
(vin) => vin.vehicle.carId === this.mainStore.order.vehicle.carId
);
if (matchingCars.length === 1) {
vehicleInfoToCommit = Object.assign(matchingCars[0].vehicle, {
vin: matchingCars[0].vin,
});
}
} else {
// No VINS found.
this.displayVinNotFoundAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "vinLookupResponse",
promise: vinLookupResponse,
}
];
// Save vehicle, customer, service and registration information
await useMainStore().saveRegistrationAddressLookup(
{
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
vehicleInfo:
Object.keys(vehicleInfoToCommit).length === 0
? useMainStore().order.vehicle
: vehicleInfoToCommit,
registrationInfo: {
firstName: this.customerQuestions.firstName,
lastName: this.customerQuestions.lastName,
address: this.customerQuestions.addressQuestions.streetAddress,
city: this.customerQuestions.addressQuestions.city,
state: this.customerQuestions.addressQuestions.state,
zipCode: this.customerQuestions.addressQuestions.zipCode,
},
},
false
);
return await this.navigateForward(carsFound);
},
async navigateForward(carsFound) {
// Match vehicles found to vehicles in state.
const matchingCars = carsFound.filter(
(car) => car.vehicle.carId === useMainStore().order.vehicle.carId
);
// If a different vehicle is found than the one entered and the selected glass is not available for that vehicle then navigate back to "vehicle-damage"
// display vehicle changed alert on that page.
if (
this.isCarIdDifferent &&
!this.isSelectedGlassAvailableForVehicle
) {
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,
{},
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
);
} else if (matchingCars.length === 1) {
await this.navigateForwardWithSingleCarMatch();
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES,
this.$route,
{},
{},
carsFound
);
}
},
resetWarningsAndErrors() {
this.displayVinNotFoundAlert = false;
this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
this.$refs.siteFooter.enableForwardAction();
},
},
mounted() {
this.attachCustomEvents();
},
computed: {
AlertMatchedDifferentVehicleHeader() {
return this.getCmsContent(
"AlertMatchedDifferentVehicleWidget",
"HeadlineText"
).replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedDifferentVehicleBody() {
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:vinYmmFound}", vinYmmFound)
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
},
AlertMatchedTwoIdenticalYMMVehicleHeader() {
return this.getCmsContent(
"AlertMatchedTwoIdenticalYMMVehicleWidget",
"HeadlineText"
).replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedTwoIdenticalYMMVehicleBody() {
const vinYmmsFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model} ${this.customAlertData?.vehicleInfo?.style}`;
const vinYmmsExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model} ${this.mainStore.order.vehicle.style}`;
return this.getCmsContent("AlertMatchedTwoIdenticalYMMVehicleWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:vinYmmsFound}", vinYmmsFound)
.replaceAll("{custom:vinYmmsExpected}", vinYmmsExpected);
},
isTwoIdenticalYMMVehicleFound(){
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return(vinYmmFound.toLowerCase()==vinYmmExpected.toLowerCase());
const resultMap = await settleAllPromises(promiseResultMap);
// If VIN Lookup by address is forbidden by State Restrictions then show an alert
if (!resultMap.vinLookupResponse.isStatePermissible) {
// State Restrictions forbid lookup by address
this.displayVinLookupByHomeAddressNotAllowedAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
}
},
watch: {
customerQuestions: {
handler(newValue) {
// if they modify one of the lookup fields (address, city, state, zipCode, or lastName), then modify the button text back to "Get my personalized quote"
const carsFound = resultMap.vinLookupResponse.vinVehicles;
// Handle cases for different amounts of VINS found for the address.
if (carsFound.length == 1) {
// Single VIN found
const carFound = carsFound[0].vehicle;
this.isCarIdDifferent = carFound.carId !== useMainStore().order.vehicle.carId;
if (this.isCarIdDifferent && carFound.carId !== this.previouslyEnteredCarId) {
// Display Alert
this.previouslyEnteredCarId = carFound.carId;
this.customAlertData.vehicleInfo = carFound;
if(this.isTwoIdenticalYMMVehicleFound){
this.displayMatchedTwoIdenticalYMMVehicleAlert = true;
this.forwardButtonCarStyle= carFound.style;
}
else{
this.displayMatchedDifferentVehicleAlert = true;
}
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
carFound.carId
);
// Update button "Continue with..."
this.$refs.siteFooter.updateButtonText(
this.getCmsContent("siteFooterWidget", "ForwardButtonText")
`Continue with ${carFound.year} ${carFound.make} ${carFound.model} ${this.forwardButtonCarStyle}`
);
this.resetWarningsAndErrors();
return this.$refs.siteFooter.removeLoader();
}
// update data
vehicleInfoToCommit = Object.assign(carFound, { vin: carsFound[0].vin });
} else if (carsFound.length > 1) {
// If multiple cars were found and one and only one of them matches the carId entered, save the vehicle info
const matchingCars = carsFound.filter(
(vin) => vin.vehicle.carId === this.mainStore.order.vehicle.carId
);
if (matchingCars.length === 1) {
vehicleInfoToCommit = Object.assign(matchingCars[0].vehicle, {
vin: matchingCars[0].vin,
});
}
} else {
// No VINS found.
this.displayVinNotFoundAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
}
// Save vehicle, customer, service and registration information
await useMainStore().saveRegistrationAddressLookup(
{
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
vehicleInfo:
Object.keys(vehicleInfoToCommit).length === 0
? useMainStore().order.vehicle
: vehicleInfoToCommit,
registrationInfo: {
firstName: this.customerQuestions.firstName,
lastName: this.customerQuestions.lastName,
address: this.customerQuestions.addressQuestions.streetAddress,
city: this.customerQuestions.addressQuestions.city,
state: this.customerQuestions.addressQuestions.state,
zipCode: this.customerQuestions.addressQuestions.zipCode,
},
},
deep: true,
false
);
return await this.navigateForward(carsFound);
},
async navigateForward(carsFound) {
// Match vehicles found to vehicles in state.
const matchingCars = carsFound.filter(
(car) => car.vehicle.carId === useMainStore().order.vehicle.carId
);
// If a different vehicle is found than the one entered and the selected glass is not available for that vehicle then navigate back to "vehicle-damage"
// display vehicle changed alert on that page.
if (
this.isCarIdDifferent &&
!this.isSelectedGlassAvailableForVehicle
) {
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,
{},
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
);
} else if (matchingCars.length === 1) {
await this.navigateForwardWithSingleCarMatch();
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES,
this.$route,
{},
{},
carsFound
);
}
},
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
customerQuestions,
textboxQuestion,
alert,
Form,
resetWarningsAndErrors() {
this.displayVinNotFoundAlert = false;
this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
this.$refs.siteFooter.enableForwardAction();
},
},
mounted() {
this.attachCustomEvents();
},
computed: {
AlertMatchedDifferentVehicleHeader() {
return this.getCmsContent(
"AlertMatchedDifferentVehicleWidget",
"HeadlineText"
).replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedDifferentVehicleBody() {
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:vinYmmFound}", vinYmmFound)
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
},
AlertMatchedTwoIdenticalYMMVehicleHeader() {
return this.getCmsContent(
"AlertMatchedTwoIdenticalYMMVehicleWidget",
"HeadlineText"
).replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedTwoIdenticalYMMVehicleBody() {
const vinYmmsFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model} ${this.customAlertData?.vehicleInfo?.style}`;
const vinYmmsExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model} ${this.mainStore.order.vehicle.style}`;
return this.getCmsContent("AlertMatchedTwoIdenticalYMMVehicleWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:vinYmmsFound}", vinYmmsFound)
.replaceAll("{custom:vinYmmsExpected}", vinYmmsExpected);
},
isTwoIdenticalYMMVehicleFound(){
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return(vinYmmFound.toLowerCase()==vinYmmExpected.toLowerCase());
}
},
watch: {
customerQuestions: {
handler(newValue) {
// if they modify one of the lookup fields (address, city, state, zipCode, or lastName), then modify the button text back to "Get my personalized quote"
this.$refs.siteFooter.updateButtonText(
this.getCmsContent("siteFooterWidget", "ForwardButtonText")
);
this.resetWarningsAndErrors();
},
deep: true,
}
},
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
customerQuestions,
textboxQuestion,
alert,
Form,
},
};
</script>
<style lang="scss">
.overflow-scroll {
height: calc(100% - 180px);
overflow-X: hidden !important;
}
</style>

View file

@ -1,5 +1,5 @@
<template>
<div class="px-5">
<div>
<alert
ref="differentVehicleAlert"
v-if="displayMatchedDifferentVehicleAlert"

View file

@ -3,18 +3,15 @@
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
ref="theForm"
v-slot="{ meta }"
>
<div class="page-container-grouped-styles ">
v-slot="{ meta }">
<div class="page-container-grouped-styles">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<div class="px-5 ">
<div class="fade-on-route-transition sub-container overflow-scroll px-5">
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<alert
cmsWidgetName="FoundMultipleVehicles"
ref="alertFoundMultipleVehicles"
@ -23,27 +20,19 @@
:manualHeadline="AlertFoundMultipleVehiclesHeader"
manualCopy=""
v-bind:isDismissible="false"
id="multiple-vehicles-alert"
/>
</div>
<div class="overflow-scroll">
<addressVehiclesQuestion
ref="addressVehiclesQuestion"
cmsWidgetName="VehicleConfirmationQuestion"
:vehicles="VehiclesForQuestions"
:vehicleSelected ="VehicleSelected"
validationRules="vehicle-required"
v-model="selectedVehicleVin"
:isCarIdDifferent="isCarIdDifferent"
:displayMatchedDifferentVehicleAlert = "displayMatchedDifferentVehicleAlert"
:displayMatchedTwoIdenticalYMMVehicleAlert = "displayMatchedTwoIdenticalYMMVehicleAlert"
/>
<div
class="alert-provide-vin my-3 px-5"
v-if="splitAlertProvideVinBodyForLink.length"
>
id="multiple-vehicles-alert" />
<addressVehiclesQuestion
ref="addressVehiclesQuestion"
cmsWidgetName="VehicleConfirmationQuestion"
:vehicles="VehiclesForQuestions"
:vehicleSelected ="VehicleSelected"
validationRules="vehicle-required"
v-model="selectedVehicleVin"
:isCarIdDifferent="isCarIdDifferent"
:displayMatchedDifferentVehicleAlert = "displayMatchedDifferentVehicleAlert"
:displayMatchedTwoIdenticalYMMVehicleAlert = "displayMatchedTwoIdenticalYMMVehicleAlert" />
<div class="alert-provide-vin my-3"
v-if="splitAlertProvideVinBodyForLink.length">
<span v-for="copy in splitAlertProvideVinBodyForLink" :key="copy">
<span v-if="doesCopyContainRouterLink(copy)" class="text-body">
<router-link
@ -51,21 +40,19 @@
query: { issPage: `${getRouterLinkRouteFromCopy(copy)}` },
name: 'root',
}"
>{{ getRouterLinkDisplayTextFromCopy(copy) }}</router-link
>
>{{ getRouterLinkDisplayTextFromCopy(copy) }}</router-link >
</span>
<span v-else class="m-0 text-body" v-html="copy"></span>
</span>
</div>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter" />
</div>
</div>
</div>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
</Form>
</template>
@ -303,9 +290,9 @@ export default {
#multiple-vehicles-alert p {
margin-bottom: 0 !important; // Overrides extra margin-bottom on alert body text
}
.overflow-scroll {
height: calc(100% - 432px);
height: calc(100% - 180px);
overflow-X: hidden !important;
}
</style>

View file

@ -1,49 +1,48 @@
<template>
<Form
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
v-slot="{ meta }"
>
<div class="page-container-grouped-styles">
<siteHeader
cmsWidgetName="SiteHeaderWidget"
/>
<div class="fade-on-route-transition sub-container overflow-scroll px-5">
<textBlock
cmsWidgetName="verifyingCoverageStatement"
typeStyle="h5"
justifyText="center"
class="mt-0 mb-4"
id="coverage-statement-text-block"
/>
<div>
<p
v-html="continueWithSchedulingBodyText"
class="mt-0 small" >
</p>
</div>
<textBlock
cmsWidgetName="whatHappensNextCopy"
class="mt-4 mb-2 fw-bold"
id="coverage-statement-text-block"
/>
<div>
<p class="small"
v-html="bodyText"
ref="coverageStatementBodyText">
</p>
</div>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<textBlock
cmsWidgetName="verifyingCoverageStatement"
typeStyle="h5"
justifyText="center"
class="mt-0 mb-4"
id="coverage-statement-text-block"
/>
<div>
<p v-html="continueWithSchedulingBodyText" class="mt-0 small" ></p>
</div>
<textBlock
cmsWidgetName="whatHappensNextCopy"
class="mt-4 mb-2 fw-bold"
id="coverage-statement-text-block"
/>
<div>
<p class="small" v-html="bodyText" ref="coverageStatementBodyText"></p>
</div>
<steeringText cmsWidgetName="MASteeringText" ></steeringText>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<recalModal ref="RecalModal" cmsWidgetName="RecalModal" />
<recalModal ref="RecalModal" cmsWidgetName="RecalModal" />
</Form>
</template>
<script>
@ -56,7 +55,7 @@ import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import textBlock from "@/digital-components/text-block/text-block";
import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal.vue';
import steeringText from "@/iss-components/steering-text/steering-text.vue";
// Import Supporting Files
import { fetchCmsContentForPage, setupModalLinks } from '@/helpers/cms-content-helper';
import { settleAllPromises } from '@/helpers/layout-helper';
@ -68,113 +67,109 @@ export default {
name: 'coverage-statement',
mixins: [baseFormMixin, vehicleQuestionsMixin],
components: {
siteFooter,
siteHeader,
siteSubHeader,
Form,
textBlock,
recalModal
},
computed: {
bodyText() {
if (useMainStore().order.damage.isRepair) {
return this.unverifiedNonADASRepairBodyText;
}
else {
let parts = useMainStore().order.lineItems.glassParts;
// if ADAS, display ADASNextSteps
if (parts.filter(part => part.requiresRecalibration).length > 0) {
return this.unverifiedADASNextStepsBodyText;
}
// if non-ADAS, display NonADASNextSteps
else {
return this.unverifiedNonADASNextStepsBodyText;
}
}
},
continueWithSchedulingBodyText() {
return this.getCmsContent("continueWithSchedulingCopy", "BodyText");
},
unverifiedADASNextStepsBodyText() {
return this.getCmsContent("UnverifiedADASNextStepsWidget", "BodyText").replaceAll("{custom:damage}", this.damageText);
},
unverifiedNonADASNextStepsBodyText() {
return this.getCmsContent("UnverifiedNonADASNextStepsWidget", "BodyText").replaceAll("{custom:damage}", this.damageText);
},
unverifiedNonADASRepairBodyText() {
return this.getCmsContent("UnverifiedNonADASRepairWidget", "BodyText");
},
damageText() {
var damageString = getDamageString();
return damageString == "match" ? "" : damageString;
},
siteFooter,
siteHeader,
siteSubHeader,
Form,
textBlock,
recalModal,
steeringText
},
mounted() {
setupModalLinks(this);
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
computed: {
bodyText() {
if (useMainStore().order.damage.isRepair) {
return this.unverifiedNonADASRepairBodyText;
}
else {
let parts = useMainStore().order.lineItems.glassParts;
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise,
// if ADAS, display ADASNextSteps
if (parts.filter(part => part.requiresRecalibration).length > 0) {
return this.unverifiedADASNextStepsBodyText;
}
// if non-ADAS, display NonADASNextSteps
else {
return this.unverifiedNonADASNextStepsBodyText;
}
}
},
];
continueWithSchedulingBodyText() {
return this.getCmsContent("continueWithSchedulingCopy", "BodyText");
},
unverifiedADASNextStepsBodyText() {
return this.getCmsContent("UnverifiedADASNextStepsWidget", "BodyText").replaceAll("{custom:damage}", this.damageText);
},
unverifiedNonADASNextStepsBodyText() {
return this.getCmsContent("UnverifiedNonADASNextStepsWidget", "BodyText").replaceAll("{custom:damage}", this.damageText);
},
unverifiedNonADASRepairBodyText() {
return this.getCmsContent("UnverifiedNonADASRepairWidget", "BodyText");
},
damageText() {
var damageString = getDamageString();
return damageString == "match" ? "" : damageString;
},
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const resultMap = await settleAllPromises(promiseResultMap);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise,
},
];
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
methods: {
arePagePrerequisitesValid() {
if (useMainStore().order.vehicle.vin) {
return true;
}
return false;
},
arePagePrerequisitesValid() {
if (useMainStore().order.vehicle.vin) {
return true;
}
return false;
},
async forwardButtonAction() {
return this.navigateForward();
},
async forwardButtonAction() {
return this.navigateForward();
},
navigateForward() {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_COVERAGE_STATEMENT,
this.$route
);
},
navigateForward() {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_COVERAGE_STATEMENT,
this.$route
);
},
},
};
</script>
<style lang="scss">
.overflow-scroll {
height: calc(100% - 168px);
overflow-X: hidden !important;
}
ol {
margin-left: -1rem;
li {
margin-bottom: .5rem;
margin-left: -1rem;
li {
margin-bottom: .5rem;
line-height: 1.5rem;
a {
line-height: 1.5rem;
a {
line-height: 1.5rem;
padding: 0;
}
padding: 0;
}
}
}
#coverage-statement-text-block {
color: #000000;
color: #000000;
}
p strong {
color: #000000;
font-weight: 500;
color: #000000;
font-weight: 500;
}
</style>
</style>

View file

@ -1,67 +1,71 @@
<template>
<Form
@submit="onSubmit"
@invalid-submit="onInvalidSubmit"
v-slot="{ meta }">
<div class="page-container-grouped-styles">
<siteHeader cms-widget-name="SiteHeaderWidget" />
<div class="fade-on-route-transition sub-container overflow-scroll mt-5 px-5">
<vehicleBanner
class="mb-3"
cms-widget-name="VehicleBannerWidget"
:display-generic-vehicle-image="false" />
<siteSubHeader cms-widget-name="SiteSubHeaderWidget" />
<alert
ref="alertVinNotFound"
v-if="displayVinNotFoundAlert"
class="mb-4"
cmsWidgetName="AlertVinNotFoundWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<alert
ref="alertMatchedDifferentVehicle"
v-if="displayMatchedDifferentVehicleAlert"
class="mb-4"
cmsWidgetName="AlertMatchedDifferentVehicleWidget"
:manualHeadline="AlertMatchedDifferentVehicleHeader"
:manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
<alert
ref="alertMatchedTwoIdenticalYMMVehicle"
v-if="displayMatchedTwoIdenticalYMMVehicleAlert"
class="mb-4"
cmsWidgetName="AlertMatchedTwoIdenticalYMMVehicleWidget"
:manualHeadline="AlertMatchedTwoIdenticalYMMVehicleHeader"
:manualCopy="AlertMatchedTwoIdenticalYMMVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
<textboxQuestion
cmsWidgetName="LicensePlateNumberQuestionWidget"
v-model="licensePlate"
isRequired
disableAutoFill
id="license-plate-question-wrapper"
inputId="license-plate-question"
validationRules="license-plate-required" />
<dropdownQuestion
cmsWidgetName="StateQuestionWidget"
v-model="licenseState"
ref="state"
inputId="8fdf9dc2e13e430eb57529499dceb3eb"
:options="stateOptions"
disableAutoFill
validationRules="state-required"
class="mt-4" />
<siteFooter
:isForwardActionDisabled="!meta.valid"
cms-widget-name="SiteFooterWidget"
@back-clicked="backButtonAction"
@forward-clicked="forwardButtonAction"
ref="siteFooter" />
</div>
</div>
</Form>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<vehicleBanner class="mb-3" cms-widget-name="VehicleBannerWidget" :display-generic-vehicle-image="false" />
<siteSubHeader cms-widget-name="SiteSubHeaderWidget" />
<alert
ref="alertVinNotFound"
v-if="displayVinNotFoundAlert"
class="mb-4"
cmsWidgetName="AlertVinNotFoundWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<alert
ref="alertMatchedDifferentVehicle"
v-if="displayMatchedDifferentVehicleAlert"
class="mb-4"
cmsWidgetName="AlertMatchedDifferentVehicleWidget"
:manualHeadline="AlertMatchedDifferentVehicleHeader"
:manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
<alert
ref="alertMatchedTwoIdenticalYMMVehicle"
v-if="displayMatchedTwoIdenticalYMMVehicleAlert"
class="mb-4"
cmsWidgetName="AlertMatchedTwoIdenticalYMMVehicleWidget"
:manualHeadline="AlertMatchedTwoIdenticalYMMVehicleHeader"
:manualCopy="AlertMatchedTwoIdenticalYMMVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
<textboxQuestion
cmsWidgetName="LicensePlateNumberQuestionWidget"
v-model="licensePlate"
isRequired
disableAutoFill
id="license-plate-question-wrapper"
inputId="license-plate-question"
validationRules="license-plate-required" />
<dropdownQuestion
cmsWidgetName="StateQuestionWidget"
v-model="licenseState"
ref="state"
inputId="8fdf9dc2e13e430eb57529499dceb3eb"
:options="stateOptions"
disableAutoFill
validationRules="state-required"
class="mt-4" />
<siteFooter
:isForwardActionDisabled="!meta.valid"
cms-widget-name="SiteFooterWidget"
@back-clicked="backButtonAction"
@forward-clicked="forwardButtonAction"
ref="siteFooter" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Form>
</template>
<script>
// Import Supporting Files
@ -92,55 +96,55 @@ defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIR
defineRule("state-required", required(errorMessages.STATE_REQUIRED));
export default {
name: 'license-plate-lookup',
mixins: [baseFormMixin, vinPagesMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
name: 'license-plate-lookup',
mixins: [baseFormMixin, vinPagesMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
data() {
return {
activeVehicleLookupAlertType: null,
vehicleFromLookup: null,
licensePlate: null,
licenseState: useMainStore().order.customer.address.state,
displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false,
displayMatchedTwoIdenticalYMMVehicleAlert: false,
previouslyEnteredCarId: "",
isCarIdDifferent: false,
customAlertData: {},
isSelectedGlassAvailableForVehicle: true,
forwardButtonCarStyle:"",
};
},
methods: {
arePagePrerequisitesValid() {
return this.mainStore.order.vehicle.carId !== null;
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
loadDefaultsFromStore() {
this.customerQuestions = this.mainStore.customerData.addressQuestions.state;
data() {
return {
activeVehicleLookupAlertType: null,
vehicleFromLookup: null,
licensePlate: null,
licenseState: useMainStore().order.customer.address.state,
displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false,
displayMatchedTwoIdenticalYMMVehicleAlert: false,
previouslyEnteredCarId: "",
isCarIdDifferent: false,
customAlertData: {},
isSelectedGlassAvailableForVehicle: true,
forwardButtonCarStyle:"",
};
},
backButtonAction() {
// route to move backwards
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
attachCustomEvents() {
methods: {
arePagePrerequisitesValid() {
return this.mainStore.order.vehicle.carId !== null;
},
loadDefaultsFromStore() {
this.customerQuestions = this.mainStore.customerData.addressQuestions.state;
},
backButtonAction() {
// route to move backwards
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
attachCustomEvents() {
this.prependActionToMethod(this, this.forwardButtonAction, () => {
this.pushEventToGA(
this.$route.query[this.queryStrings.ISS_PAGE],
@ -149,179 +153,174 @@ export default {
true
);
});
},
// NOTE: If form is not valid, this method is not called when 'Continue' button is clicked
async forwardButtonAction() {
this.resetWarningsAndErrors();
// Lookup VIN
const vinLookupResponse = await useMainStore().lookupVinByPlate(
this.licensePlate, this.licenseState);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "vinLookupResponse",
promise: vinLookupResponse,
},
];
// NOTE: If form is not valid, this method is not called when 'Continue' button is clicked
async forwardButtonAction() {
this.resetWarningsAndErrors();
const resultMap = await settleAllPromises(promiseResultMap);
// Lookup VIN
const vinLookupResponse = await useMainStore().lookupVinByPlate(
this.licensePlate, this.licenseState);
// No VIN found
if (resultMap.vinLookupResponse.error) {
this.displayVinNotFoundAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
};
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "vinLookupResponse",
promise: vinLookupResponse,
},
];
// Vehicle found from VIN lookup
const vehicleFromLookup = resultMap.vinLookupResponse.vehicle;
const resultMap = await settleAllPromises(promiseResultMap);
// Check if the CarId has changed
this.isCarIdDifferent =
vehicleFromLookup.carId !== useMainStore().order.vehicle.carId;
// Handle changing car
if (
this.isCarIdDifferent &&
vehicleFromLookup.carId !== this.previouslyEnteredCarId
) {
// Display Alert
this.previouslyEnteredCarId = vehicleFromLookup.carId;
this.customAlertData.vehicleInfo = vehicleFromLookup;
// No VIN found
if (resultMap.vinLookupResponse.error) {
this.displayVinNotFoundAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
};
if(this.isTwoIdenticalYMMVehicleFound){
this.displayMatchedTwoIdenticalYMMVehicleAlert = true;
this.forwardButtonCarStyle= vehicleFromLookup.style;
}
else{
this.displayMatchedDifferentVehicleAlert = true;
}
// Vehicle found from VIN lookup
const vehicleFromLookup = resultMap.vinLookupResponse.vehicle;
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
vehicleFromLookup.carId
);
// Check if the CarId has changed
this.isCarIdDifferent =
vehicleFromLookup.carId !== useMainStore().order.vehicle.carId;
// Handle changing car
if (
this.isCarIdDifferent &&
vehicleFromLookup.carId !== this.previouslyEnteredCarId
) {
// Display Alert
this.previouslyEnteredCarId = vehicleFromLookup.carId;
this.customAlertData.vehicleInfo = vehicleFromLookup;
// Update button "Continue with..."
this.$refs.siteFooter.updateButtonText(`Continue with ${vehicleFromLookup.year} ${vehicleFromLookup.make} ${vehicleFromLookup.model} ${this.forwardButtonCarStyle}`);
return this.$refs.siteFooter.removeLoader();
}
if(this.isTwoIdenticalYMMVehicleFound){
this.displayMatchedTwoIdenticalYMMVehicleAlert = true;
this.forwardButtonCarStyle= vehicleFromLookup.style;
}
else{
this.displayMatchedDifferentVehicleAlert = true;
}
// Save vehicle, license plate, and registration information
await useMainStore().saveRegistrationLicensePlateLookup(
{
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
vehicleInfo: Object.assign(vinLookupResponse.data.vehicle, { vin: vinLookupResponse.data.vin }),
registrationInfo: {
licensePlate: this.licensePlate,
state: this.licenseState,
},
},
false
);
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
vehicleFromLookup.carId
);
return await this.navigateForward();
},
async navigateForward() {
// If a different vehicle is found than the one entered and the selected glass is not available for that vehicle then navigate back to "vehicle-damage"
// display vehicle changed alert on that page.
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,
{},
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
);
} else {
await this.navigateForwardWithSingleCarMatch();
}
},
resetWarningsAndErrors() {
this.displayVinNotFoundAlert = false;
this.displayMatchedDifferentVehicleAlert = false;
},
},
mounted() {
this.attachCustomEvents();
this.loadDefaultsFromStore();
},
computed: {
AlertMatchedDifferentVehicleHeader() {
return this.getCmsContent(
"AlertMatchedDifferentVehicleWidget",
"HeadlineText"
).replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedDifferentVehicleBody() {
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
// Update button "Continue with..."
this.$refs.siteFooter.updateButtonText(`Continue with ${vehicleFromLookup.year} ${vehicleFromLookup.make} ${vehicleFromLookup.model} ${this.forwardButtonCarStyle}`);
return this.$refs.siteFooter.removeLoader();
}
return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
// Save vehicle, license plate, and registration information
await useMainStore().saveRegistrationLicensePlateLookup(
{
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
vehicleInfo: Object.assign(vinLookupResponse.data.vehicle, { vin: vinLookupResponse.data.vin }),
registrationInfo: {
licensePlate: this.licensePlate,
state: this.licenseState,
},
},
false
);
return await this.navigateForward();
},
async navigateForward() {
// If a different vehicle is found than the one entered and the selected glass is not available for that vehicle then navigate back to "vehicle-damage"
// display vehicle changed alert on that page.
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,
{},
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
);
} else {
await this.navigateForwardWithSingleCarMatch();
}
},
resetWarningsAndErrors() {
this.displayVinNotFoundAlert = false;
this.displayMatchedDifferentVehicleAlert = false;
},
},
mounted() {
this.attachCustomEvents();
this.loadDefaultsFromStore();
},
computed: {
AlertMatchedDifferentVehicleHeader() {
return this.getCmsContent(
"AlertMatchedDifferentVehicleWidget",
"HeadlineText"
).replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedDifferentVehicleBody() {
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return this.getCmsContent("AlertMatchedDifferentVehicleWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:vinYmmFound}", vinYmmFound)
.replaceAll("{custom:vinYmmExpected}", vinYmmExpected);
},
AlertMatchedTwoIdenticalYMMVehicleHeader() {
return this.getCmsContent(
"AlertMatchedTwoIdenticalYMMVehicleWidget",
"HeadlineText"
).replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedTwoIdenticalYMMVehicleBody() {
const vinYmmsFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model} ${this.customAlertData?.vehicleInfo?.style}`;
const vinYmmsExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model} ${this.mainStore.order.vehicle.style}`;
},
AlertMatchedTwoIdenticalYMMVehicleHeader() {
return this.getCmsContent(
"AlertMatchedTwoIdenticalYMMVehicleWidget",
"HeadlineText"
).replaceAll("{custom:damage}", getDamageString());
},
AlertMatchedTwoIdenticalYMMVehicleBody() {
const vinYmmsFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model} ${this.customAlertData?.vehicleInfo?.style}`;
const vinYmmsExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model} ${this.mainStore.order.vehicle.style}`;
return this.getCmsContent("AlertMatchedTwoIdenticalYMMVehicleWidget", "BodyText")
return this.getCmsContent("AlertMatchedTwoIdenticalYMMVehicleWidget", "BodyText")
.replaceAll("{custom:damage}", getDamageString())
.replaceAll("{custom:vinYmmsFound}", vinYmmsFound)
.replaceAll("{custom:vinYmmsExpected}", vinYmmsExpected);
},
isTwoIdenticalYMMVehicleFound(){
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return(vinYmmFound.toLowerCase()==vinYmmExpected.toLowerCase());
},
isTwoIdenticalYMMVehicleFound(){
const vinYmmFound = `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return(vinYmmFound.toLowerCase()==vinYmmExpected.toLowerCase());
},
stateOptions: {
get: function () {
return states;
},
},
},
stateOptions: {
get: function () {
return states;
watch: {
licensePlate() {
this.$refs.siteFooter.updateButtonText(
this.getCmsContent("SiteFooterWidget", "ForwardButtonText")
);
},
registrationZipCode() {
this.$refs.siteFooter.updateButtonText(
this.getCmsContent("SiteFooterWidget", "ForwardButtonText")
);
},
},
},
},
watch: {
licensePlate() {
this.$refs.siteFooter.updateButtonText(
this.getCmsContent("SiteFooterWidget", "ForwardButtonText")
);
},
registrationZipCode() {
this.$refs.siteFooter.updateButtonText(
this.getCmsContent("SiteFooterWidget", "ForwardButtonText")
);
},
},
components: {
Form,
siteFooter,
siteHeader,
siteSubHeader,
vehicleBanner,
textboxQuestion,
dropdownQuestion,
alert
},
};
</script>
components: {
Form,
siteFooter,
siteHeader,
siteSubHeader,
vehicleBanner,
textboxQuestion,
dropdownQuestion,
alert
},
};
</script>
<style>
.overflow-scroll {
height: calc(100% - 220px);
overflow-x: hidden !important;
}
#license-plate-question-wrapper .form-test-error {
/**
Override extra margin-bottom in the error message in TextboxQuestion
*/
margin-bottom: 0 !important;
}
</style>
<style lang="scss">
#license-plate-question-wrapper .form-test-error {
/**
Override extra margin-bottom in the error message in TextboxQuestion
*/
margin-bottom: 0 !important;
}
</style>

View file

@ -1,13 +1,14 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles ">
<siteHeader cmsWidgetName="SiteHeaderWidget"/>
<div class="fade-on-route-transition px-5 overflow-scroll">
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" id="sub-header"/>
<addressQuestions ref="addressQuestions" v-model="customerQuestions.addressQuestions" includeStreetAddress2="true" id="address-questions-wrapper"/>
<div class="row mt-4 ">
<div class="col">
<textboxQuestion
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget"/>
<div class="container-fluid pb-2">
<div class="row mt-4 px-3">
<div class="col">
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" id="sub-header"/>
<addressQuestions ref="addressQuestions" v-model="customerQuestions.addressQuestions" includeStreetAddress2="true" id="address-questions-wrapper"/>
<textboxQuestion
inputId="firstNameField"
cmsWidgetName="PolicyholderFirstNameQuestion"
v-model="customerQuestions.firstName"
@ -15,11 +16,7 @@
ref="policyHolderFirstName"
disableAutoFill
validationRules="first-name-required" />
</div>
</div>
<div class="row mt-4 mb-2">
<div class="col">
<textboxQuestion
<textboxQuestion
inputId="lastNameField"
cmsWidgetName="PolicyholderLastNameQuestion"
v-model="customerQuestions.lastName"
@ -27,15 +24,16 @@
ref="policyHolderLastName"
disableAutoFill
validationRules="last-name-required" />
</div>
</div>
<siteFooter
</div>
</div>
<siteFooter
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
:isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@back-clicked="backButtonAction"
/>
/>
</div>
</div>
</div>
</Form>
@ -60,7 +58,7 @@ import { useMainStore } from '@/store';
//define validation rules
defineRule("first-name-required", required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED));
defineRule("last-name-required", required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED));
export default {
name: "policy-holder-details",
mixins: [BaseFormMixin],
@ -73,94 +71,90 @@ export default {
const mainStore = useMainStore();
return { mainStore };
},
async beforeRouteEnter(to, from, next)
async beforeRouteEnter(to, from, next)
{
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},];
//use resultMap to populate layout content.
let resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
methods:
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},];
backButtonAction() {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
//use resultMap to populate layout content.
let resultMap = await settleAllPromises(promiseResultMap);
forwardButtonAction()
{
this.mainStore.updatePolicyHolderDetails(this.customerQuestions);
return this.navigateForward();
},
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
methods:
navigateForward() {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_HOLDER_DETAILS,
this.$route
);
},
getPolicyHolderDetailsFromStore() {
return {
addressQuestions :
{
streetAddress: this.mainStore.order.customer.address.streetAddress,
streetAddress2: this.mainStore.order.customer.address.streetAddress2,
city: this.mainStore.order.customer.address.city,
state: this.mainStore.order.customer.address.state,
zipCode: this.mainStore.order.customer.address.zipCode,
},
firstName : this.mainStore.order.customer.firstName,
lastName : this.mainStore.order.customer.lastName,
}
},
},
components: {
siteHeader,
siteSubHeader,
textboxQuestion,
addressQuestions,
siteFooter,
Form,
},
}
</script>
<style lang="scss">
.alert.alert-warning
{
backButtonAction() {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
forwardButtonAction()
{
this.mainStore.updatePolicyHolderDetails(this.customerQuestions);
return this.navigateForward();
},
margin-top: 20px;
}
navigateForward() {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_HOLDER_DETAILS,
this.$route
);
},
getPolicyHolderDetailsFromStore() {
return {
addressQuestions :
{
streetAddress: this.mainStore.order.customer.address.streetAddress,
streetAddress2: this.mainStore.order.customer.address.streetAddress2,
city: this.mainStore.order.customer.address.city,
state: this.mainStore.order.customer.address.state,
zipCode: this.mainStore.order.customer.address.zipCode,
},
firstName : this.mainStore.order.customer.firstName,
lastName : this.mainStore.order.customer.lastName,
}
},
},
components: {
siteHeader,
siteSubHeader,
textboxQuestion,
addressQuestions,
siteFooter,
Form,
},
}
</script>
<style lang="scss">
.overflow-scroll {
height: calc(100% - 168px);
overflow-X: hidden !important;
}
.alert.alert-warning
{
margin-top: 20px;
}
#sub-header p {
font-size: 16px;
line-height: 26px;
color: #4D5151;
}
#sub-header p {
font-size: 16px;
line-height: 26px;
color: #4D5151;
}
#address-questions-wrapper {
margin-top: 24px;
}
#address-questions-wrapper {
margin-top: 24px;
}
#address-questions-wrapper .alert.heading {
line-height: 24px;
}
#address-questions-wrapper .alert.heading {
line-height: 24px;
}
#address-questions-wrapper .form-test-error {
line-height: 24px;
}
</style>
#address-questions-wrapper .form-test-error {
line-height: 24px;
}
</style>

View file

@ -1,35 +1,44 @@
<template>
<Form @submit="onSubmit" @invalidSubmit="onInvalidSubmit" v-slot="{ meta }">
<div class="page-container-grouped-styles overflow-auto">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<siteSubHeader cmsWidgetName="SiteSubHeader" id="sub-header" />
<div class="fade-on-route-transition sub-container make-tall px-5">
<div v-html="ProviderPreferenceHeaderText" class="text-center mt-4 mb-4" ></div>
<div
v-html="ProviderPreferenceBodyText"
class="mt-0"
></div>
<shoppreferenceModal cmsWidgetName="ShopPreferenceDrawer" />
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<siteSubHeader cmsWidgetName="SiteSubHeader" id="sub-header" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<div v-html="ProviderPreferenceHeaderText" class="text-center mb-5 modal-link" ></div>
<div
v-html="ProviderPreferenceBodyText"
class="mt-0 body-text"
></div>
<shoppreferenceModal cmsWidgetName="ShopPreferenceDrawer" />
<buttonQuestion
cmsWidgetName="ServiceLocationQuestion"
:questionText="questionText"
:answers="answersFromCms"
buttonTypeString="listButton"
isRequired
v-model="SelectedshopLocation"
validationRules="questions-required" />
<buttonQuestion
cmsWidgetName="ServiceLocationQuestion"
:questionText="questionText"
:answers="answersFromCms"
buttonTypeString="listButton"
isRequired
v-model="SelectedshopLocation"
validationRules="questions-required" />
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
</div>
</div>
</Form>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Form>
</template>
<script>
// Import Supporting Files
@ -50,75 +59,93 @@ import shoppreferenceModal from '@/layouts/provider-preference/shoppreference-mo
// DEFINE VALIDATION RULES
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
export default {
name: "provider-preference",
mixins: [baseFormMixin],
components: {
siteFooter,
siteHeader,
siteSubHeader,
Form,
shoppreferenceModal,
buttonQuestion
},
data() {
return {
SelectedshopLocation : null,
};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
computed: {
isForwardActionDisabled() {
return this.SelectedshopLocation === null;
name: "provider-preference",
mixins: [baseFormMixin],
components: {
siteFooter,
siteHeader,
siteSubHeader,
Form,
shoppreferenceModal,
buttonQuestion
},
ProviderPreferenceHeaderText(){
return this.getCmsContent("ProviderPreference", "HeaderText");
data() {
return {
SelectedshopLocation : null,
};
},
ProviderPreferenceBodyText(){
return this.getCmsContent("ProviderPreference", "BodyText");
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
questionText() {
computed: {
isForwardActionDisabled() {
return this.SelectedshopLocation === null;
},
ProviderPreferenceHeaderText(){
return this.getCmsContent("ProviderPreference", "HeaderText");
},
ProviderPreferenceBodyText(){
return this.getCmsContent("ProviderPreference", "BodyText");
},
questionText() {
return this.getCmsContent("ServiceLocationQuestion", "QuestionText");
},
answersFromCms() {
answersFromCms() {
return this.getCmsContent("ServiceLocationQuestion", "Answers");
},
},
methods: {
arePagePrerequisiteValid() {
return true;
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
methods: {
arePagePrerequisiteValid() {
return true;
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
forwardButtonAction() {
if(this.SelectedshopLocation == "Schedule with Safelite")
{
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route);
}
},
resetDependentState() {},
},
forwardButtonAction() {
if(this.SelectedshopLocation == "Schedule with Safelite")
{
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route);
}
},
resetDependentState() {},
},
};
</script>
<style lang="scss">
#sub-header span{
color: #000000;
color: $black;
}
</style>
.body-text {
color: $darker-gray;
p, li {
margin-bottom: 0.5rem;
}
}
.modal-link a{
color: $blue-700;
font-size: 14px;
line-height: 24px;
font-weight: 500;
}
.question-text {
margin-top: 0;
& > span {
text-align: left;
}
}
</style>

View file

@ -17,8 +17,8 @@
aria-label="Close"></button>
</div>
<div class="modal-body ps-4 pe-4 pt-4 pb-4">
<h5 class="mb-4 text-center header-text" v-html="ModalHeadline"></h5>
<p class="mb-0 small" v-html="ModalBodyText"></p>
<h5 class="mb-2 text-center header-text" v-html="ModalHeadline"></h5>
<p class="mb-0 small body-text" v-html="ModalBodyText"></p>
</div>
<div class="modal-footer px-5 py-4">
<buttonMain
@ -74,7 +74,13 @@ export default {
.header-text{
color: #000000;
font-weight: 500;
font-size: 16px;
line-height: 26px;
}
.body-text{
color:#525656;
font-size: 16px;
line-height: 26px;
}
.modal-header {
border-bottom: none;

View file

@ -0,0 +1,32 @@
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import serviceLocationModal from "@/layouts/service-location/service-location.vue";
describe("navigation", () => {
test("if the back button is clicked, navigate back", async () => {
// Arrange
const { wrapper } = setupMocks({
});
// Act
await wrapper.vm.backButtonAction();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
});
});
function setupMocks()
{
const wrapper = shallowMount(
serviceLocationModal,
getMountOptions({
router: {
navigate: jest.fn(),
},
})
);
return { wrapper };
}

View file

@ -1,71 +1,152 @@
<template>
<div>
<Form @submit="onSubmit" @invalidSubmit="onInvalidSubmit" v-slot="{ meta }">
<div class="page-container-grouped-styles overflow-auto">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall px-5">
<p>Placeholder for service-location page</p>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
</div>
</div>
</Form>
</div>
</template>
<script>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles">
<siteHeader cmsWidgetName="SiteHeaderWidget" class="siteHeader"/>
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" id="sub-header" />
<div class="fade-on-route-transition position-relative px-5 choose-option">
<buttonQuestion
cmsWidgetName="ServiceTypeQuestionWidget"
:questionText="questionText"
:answers="answersFromCms"
buttonTypeString="listCard"
isRequired
v-model="selectedValues"
validationRules="selection-required"/>
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Form>
</template>
<script>
// Import Supporting Files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import buttonQuestion from "@/digital-components/button-question/button-question";
// Import Component
import baseFormMixin from "@/mixins/base-form-mixin";
import { Form } from "vee-validate";
import { Form, defineRule } from "vee-validate";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import siteHeader from "@/iss-components/site-header/site-header.vue";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
// DEFINE VALIDATION RULES
defineRule("selection-required", required(errorMessages.OPTION_REQUIRED));
export default {
name: "provider-preference",
mixins: [baseFormMixin],
components: {
siteFooter,
siteHeader,
siteSubHeader,
Form,
},
data() {
return {};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
methods: {
arePagePrerequisiteValid() {
return true;
name: "service-location",
mixins: [baseFormMixin],
components: {
siteFooter,
siteHeader,
siteSubHeader,
buttonQuestion,
Form,
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
data() {
return {};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [{
resultKey: "cmsContent",
promise: cmsContentPromise,
}, ];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
computed: {
questionText() {
return this.getCmsContent("ServiceTypeQuestionWidget", "QuestionText");
},
answersFromCms() {
return this.getCmsContent("ServiceTypeQuestionWidget", "Answers");
},
},
methods: {
arePagePrerequisiteValid() {
return true;
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {},
resetDependentState() {},
},
async forwardButtonAction() {},
resetDependentState() {},
},
};
</script>
</script>
<style lang="scss">
.fade-on-route-transition {
margin-bottom: 100px;
}
.page-container-grouped-styles {
overflow: auto;
}
.modal-open {
.page-container-grouped-styles {
overflow: hidden;
}
}
#sub-header span {
color: $black;
}
.question-text {
& > span {
line-height: 1.500rem;
}
}
.list-card-content p {
&:first-of-type {
line-height: 1.5rem;
}
&:not(:nth-of-type(1)){
line-height: 1.250rem;
}
}
.siteHeader{
.site-header{
margin-bottom: 1.25rem !important;
}
}
.choose-option{
.button-question >div {
&:first-of-type {
margin-bottom: 0.95rem;
line-height: 1.500rem;
}
}
}
.button-question{
.row.form-test-error{
line-height:1.500rem;
padding-left: 0rem !important;
}
}
</style>

View file

@ -1,58 +1,64 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles vehicle-damage">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="fade-on-route-transition sub-container overflow-scroll">
<alert
ref="vehicleChangeAlert"
v-if="shouldDisplayVehicleChangeAlert"
class="mt-5 mb-0"
cmsWidgetName="VehicleChangeAlert"
alertClass="alert-warning"
:isDismissible="false" />
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<damageLocationQuestion
ref="damageLocation"
cmsWidgetName="DamageLocationQuestion"
v-model="selectedDamageLocations"
groupName="DamageLocationQuestion" />
<windshieldOptions
ref="windshieldOptions"
v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations" />
<alert
v-if="hasRepairReplaceConflict"
class="my-5"
cmsWidgetName="HasReplacementConflict"
alertClass="alert-danger"
:isDismissible="false" />
<sideDoorOptions
ref="sideDoorOptions"
cmsWidgetName="SideDoorSideQuestion"
groupName="SideDoorSideQuestion"
v-model="sideDoorOptionsData"
v-show="!hasRepairReplaceConflict"
:selectedDamageLocations="selectedDamageLocations" />
<replaceOptionsQuestion
ref="backGlassOptions"
cmsWidgetName="RearReplaceOptionsQuestion"
:isAvailable="isRearWindowDamageLocation && !hasRepairReplaceConflict"
v-model="selectedRearReplaceOptions"
groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required" />
<site-footer
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget"/>
<div class="container-fluid pb-2">
<div class="row mt-4 px-3">
<div class="col">
<alert
ref="vehicleChangeAlert"
v-if="shouldDisplayVehicleChangeAlert"
class="mt-5 mb-0"
cmsWidgetName="VehicleChangeAlert"
alertClass="alert-warning"
:isDismissible="false" />
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<damageLocationQuestion
ref="damageLocation"
cmsWidgetName="DamageLocationQuestion"
v-model="selectedDamageLocations"
groupName="DamageLocationQuestion" />
<windshieldOptions
ref="windshieldOptions"
v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations" />
<alert
v-if="hasRepairReplaceConflict"
class="my-5"
cmsWidgetName="HasReplacementConflict"
alertClass="alert-danger"
:isDismissible="false" />
<sideDoorOptions
ref="sideDoorOptions"
cmsWidgetName="SideDoorSideQuestion"
groupName="SideDoorSideQuestion"
v-model="sideDoorOptionsData"
v-show="!hasRepairReplaceConflict"
:selectedDamageLocations="selectedDamageLocations" />
<replaceOptionsQuestion
ref="backGlassOptions"
cmsWidgetName="RearReplaceOptionsQuestion"
:isAvailable="isRearWindowDamageLocation && !hasRepairReplaceConflict"
v-model="selectedRearReplaceOptions"
groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required" />
<site-footer
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
</div>
</div>
</div>
</div>
</div>
</Form>
@ -207,7 +213,7 @@ export default {
})
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.SINGLE
);
@ -222,7 +228,7 @@ export default {
})
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.DRIVER
);
@ -237,7 +243,7 @@ export default {
})
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.PASSENGER
);
@ -302,147 +308,147 @@ export default {
async forwardButtonAction() {
await this.mainStore.saveVehicleDamage(this.isWindshieldRepair,
this.selectedGlassToReplace(),
this.selectedWindshieldOptions.selectedWindshieldChipCount);
return this.navigateForward();
},
this.selectedGlassToReplace(),
this.selectedWindshieldOptions.selectedWindshieldChipCount);
return this.navigateForward();
},
navigateForward() {
if (this.mainStore.damage.isRepair) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR,
this.$route
);
}
else {
// If vin already exists, navigate directly to vin-lookup
if (this.mainStore.order.vehicle.vin) {
navigateForward() {
if (this.mainStore.damage.isRepair) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR,
this.$route
);
}
}
},
selectedGlassToReplace() {
const selectedGlassToReplace = [];
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair) {
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(
(wsItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.WINDSHIELD,
glassName: wsItem,
});
else {
// If vin already exists, navigate directly to vin-lookup
if (this.mainStore.order.vehicle.vin) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
this.$route
);
}
);
}
}
},
if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.DRIVER,
glassName: driverItem,
selectedGlassToReplace() {
const selectedGlassToReplace = [];
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair) {
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(
(wsItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.WINDSHIELD,
glassName: wsItem,
});
}
);
}
if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.DRIVER,
glassName: driverItem,
});
});
}
if (this.isPassengerSideReplace) {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(
(passengerItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.PASSENGER,
glassName: passengerItem,
});
}
);
}
if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.REAR,
glassName: this.selectedRearReplaceOptions,
});
}
return selectedGlassToReplace;
},
},
computed: {
isWindshieldDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD;
});
}
if (this.isPassengerSideReplace) {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(
(passengerItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.PASSENGER,
glassName: passengerItem,
});
}
);
}
if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.REAR,
glassName: this.selectedRearReplaceOptions,
},
isSideDoorDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR;
});
}
return selectedGlassToReplace;
},
},
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() {
return (
this.isWindshieldDamageLocation &&
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
},
isRearWindowDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW;
});
},
isWindshieldRepair() {
return (
this.isWindshieldDamageLocation &&
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR
);
},
isDriverSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
);
},
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((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
);
},
hasSplitSingleConflict() {
if (
!this.selectedDamageLocations?.includes("Windshield") ||
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
return this.sideDoorOptionsData.selectedDoorSides.some((selectedPassengerSide) => {
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
});
},
hasRepairReplaceConflict() {
return (
this.isWindshieldDamageLocation &&
this.selectedDamageLocations.length > 1 &&
this.isWindshieldRepair
);
},
hasSplitSingleConflict() {
if (
!this.selectedDamageLocations?.includes("Windshield") ||
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR ||
!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
)
!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
)
return false;
return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedSingleWindshield) => {
return (
selectedSingleWindshield.toUpperCase() ===
damageLocationsSelected.SINGLE.toUpperCase()
);
}
) &&
(this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedDriverWindshield) => {
return (
selectedDriverWindshield.toUpperCase() ===
damageLocationsSelected.DRIVER.toUpperCase()
);
}
) ||
return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedSingleWindshield) => {
return (
selectedSingleWindshield.toUpperCase() ===
damageLocationsSelected.SINGLE.toUpperCase()
);
}
) &&
(this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedDriverWindshield) => {
return (
selectedDriverWindshield.toUpperCase() ===
damageLocationsSelected.DRIVER.toUpperCase()
);
}
) ||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedPassengerWindshield) => {
return (
@ -451,31 +457,24 @@ export default {
);
}
))
);
);
},
shouldDisplayVehicleChangeAlert() {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
}
},
shouldDisplayVehicleChangeAlert() {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
}
},
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
sideDoorOptions,
damageLocationQuestion,
windshieldOptions,
replaceOptionsQuestion,
Form,
alert,
},
};
</script>
<style lang="scss">
.overflow-scroll {
height: calc(100% - 180px);
overflow-X: hidden !important;
}
</style>
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
sideDoorOptions,
damageLocationQuestion,
windshieldOptions,
replaceOptionsQuestion,
Form,
alert,
},
};
</script>

View file

@ -1,36 +1,25 @@
<template>
<Form
@submit="onSubmit"
@invalid-submit="onInvalidSubmit"
>
<div class="page-container-grouped-styles vehicle-lookup">
<SiteHeader
cms-widget-name="SiteHeaderWidget"
/>
<div class="fade-on-route-transition sub-container overflow-scroll container gx-0">
<VehicleBanner
class="mb-3"
cms-widget-name="VehicleBannerWidget"
:display-generic-vehicle-image="false"
/>
<SiteSubHeader
cms-widget-name="SiteSubHeaderWidget"
/>
<VinLookupMethods
v-model="selectedVinLookupMethod"
cms-widget-name="VINLookupMethod"
group-name="VinLookupMethods"
ref="VinLookupMethods"
/>
<SiteFooter
cms-widget-name="SiteFooterWidget"
:is-forward-action-disabled="isForwardActionDisabled"
@back-clicked="backButtonAction"
@forward-clicked="forwardButtonAction"
/>
</div>
</div>
</Form>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit">
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<VehicleBanner class="mb-3" cms-widget-name="VehicleBannerWidget" :display-generic-vehicle-image="false" />
<SiteSubHeader cms-widget-name="SiteSubHeaderWidget" />
<VinLookupMethods v-model="selectedVinLookupMethod" cms-widget-name="VINLookupMethod" group-name="VinLookupMethods" ref="VinLookupMethods" />
<SiteFooter cms-widget-name="SiteFooterWidget" :is-forward-action-disabled="isForwardActionDisabled" @back-clicked="backButtonAction" @forward-clicked="forwardButtonAction" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Form>
</template>
<script>
// Import Supporting Files
@ -49,78 +38,71 @@ import VehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import VinLookupMethods from './vin-lookup-methods/vin-lookup-methods.vue';
export default {
name: 'vehicle-lookup',
mixins: [BaseFormMixin],
components: {
Form,
SiteFooter,
SiteHeader,
SiteSubHeader,
VehicleBanner,
VinLookupMethods,
},
data() {
return {
selectedVinLookupMethod: null,
};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
name: 'vehicle-lookup',
mixins: [BaseFormMixin],
components: {
Form,
SiteFooter,
SiteHeader,
SiteSubHeader,
VehicleBanner,
VinLookupMethods,
},
data() {
return {
selectedVinLookupMethod: null,
};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.VinLookupMethods.initializeComponent();
});
},
computed: {
isForwardActionDisabled() {
return this.selectedVinLookupMethod === null;
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.VinLookupMethods.initializeComponent();
});
},
},
methods: {
arePagePrerequisiteValid() {
return true;
computed: {
isForwardActionDisabled() {
return this.selectedVinLookupMethod === null;
},
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
methods: {
arePagePrerequisiteValid() {
return true;
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
forwardButtonAction() {
switch (this.selectedVinLookupMethod) {
case vinLookupMethodSelections.MANUALVIN:
useMainStore().updateVehicleVin(null);
this.$router.navigate(this.navigationScenarios.SELECTED_MANUAL_VIN, this.$route);
break;
case vinLookupMethodSelections.LICENSEPLATE:
this.$router.navigate(this.navigationScenarios.SELECTED_LICENSE_PLATE, this.$route);
break;
case vinLookupMethodSelections.HOMEADDRESS:
this.$router.navigate(this.navigationScenarios.SELECTED_HOME_ADDRESS, this.$route);
break;
default:
break;
}
},
resetDependentState() {},
},
forwardButtonAction() {
switch (this.selectedVinLookupMethod) {
case vinLookupMethodSelections.MANUALVIN:
useMainStore().updateVehicleVin(null);
this.$router.navigate(this.navigationScenarios.SELECTED_MANUAL_VIN, this.$route);
break;
case vinLookupMethodSelections.LICENSEPLATE:
this.$router.navigate(this.navigationScenarios.SELECTED_LICENSE_PLATE, this.$route);
break;
case vinLookupMethodSelections.HOMEADDRESS:
this.$router.navigate(this.navigationScenarios.SELECTED_HOME_ADDRESS, this.$route);
break;
default:
break;
}
},
resetDependentState() {},
},
};
</script>
<style lang="scss">
.overflow-scroll {
height: calc(100% - 180px);
overflow-X: hidden !important;
}
</style>

View file

@ -1,51 +1,47 @@
<template>
<div class="page-container-grouped-styles">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner class="mb-3" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true"/>
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
:hasBackButton="true"
@click-event="backButtonAction"
/>
<div class="fade-on-route-transition">
<makeQuestion
class="fade-on-route-transition"
v-model="selectedMake"
ref="makeQuestion"
cmsWidgetName="VehicleMakeQuestion"
/>
</div>
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
@back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
<div class="page-container-grouped-styles position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mb-3" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" :hasBackButton="true" @click-event="backButtonAction" />
<makeQuestion class="px-4" v-model="selectedMake" ref="makeQuestion" cmsWidgetName="VehicleMakeQuestion" />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" @back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
// Components
import makeQuestion from "@/layouts/vehicle-make/make-question/make-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
import siteFooter from "@/iss-components/site-footer/site-footer";
// Components
import makeQuestion from "@/layouts/vehicle-make/make-question/make-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
import siteFooter from "@/iss-components/site-footer/site-footer";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
export default {
name: 'vehicle-make',
data() {
return {
selectedMake: null,
shouldHideForwardButton: true
};
},
export default {
name: 'vehicle-make',
data() {
return {
selectedMake: null,
shouldHideForwardButton: true
};
},
async beforeRouteEnter(to, from, next) {
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const makeQuestionInitialDataPromise = makeQuestion.methods.loadInitialData();
@ -53,12 +49,12 @@
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "makeQuestionInitialData",
promise: makeQuestionInitialDataPromise,
resultKey: "makeQuestionInitialData",
promise: makeQuestionInitialDataPromise,
},
];
@ -71,36 +67,36 @@
resultMap.makeQuestionInitialData
);
});
},
methods: {
backButtonAction() {
},
methods: {
backButtonAction() {
this.$router.navigate(
this.navigationScenarios.CLICKED_BACK,
this.$route
this.navigationScenarios.CLICKED_BACK,
this.$route
);
},
arePagePrerequisitesValid() {
},
arePagePrerequisitesValid() {
if (this.mainStore.order.vehicle.year){
return true;
return true;
}
return false;
},
},
components: {
makeQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
},
watch: {
selectedMake(make) {
},
components: {
makeQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
},
watch: {
selectedMake(make) {
this.mainStore.updateVehicleMake( make );
this.$router.navigate(
this.navigationScenarios.SELECTED_MAKE,
this.$route
this.navigationScenarios.SELECTED_MAKE,
this.$route
);
},
}
};
},
}
};
</script>

View file

@ -1,80 +1,80 @@
<template>
<div class="page-container-grouped-styles">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner class="mb-3" cmsWidgetName="VehicleBannerWidget" displayGenericVehicleImage />
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
:hasBackButton="true"
:backButtonAccessibleText="backButtonAccessibleText"
@click-event="backButtonAction"
/>
<div class="fade-on-route-transition">
<modelQuestion v-model="selectedModel" ref="modelQuestion" cmsWidgetName="VehicleModelQuestion" />
</div>
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
@back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
<div class="page-container-grouped-styles position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mb-3" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" :hasBackButton="true" :backButtonAccessibleText="backButtonAccessibleText" @click-event="backButtonAction" />
<modelQuestion v-model="selectedModel" ref="modelQuestion" cmsWidgetName="VehicleModelQuestion" class="px-4" />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" @back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
</template>
<script>
// Components
import modelQuestion from "@/layouts/vehicle-model/model-question/model-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
import siteFooter from "@/iss-components/site-footer/site-footer";
<script>
// Components
import modelQuestion from "@/layouts/vehicle-model/model-question/model-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
import siteFooter from "@/iss-components/site-footer/site-footer";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
export default {
export default {
name: "vehicle-model",
data() {
return {
selectedModel: null,
shouldHideForwardButton: true
};
return {
selectedModel: null,
shouldHideForwardButton: true
};
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const modelQuestionInitialDataPromise =
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const modelQuestionInitialDataPromise =
modelQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "modelQuestionInitialData",
promise: modelQuestionInitialDataPromise,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "modelQuestionInitialData",
promise: modelQuestionInitialDataPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.modelQuestion.initializeComponent(
resultMap.modelQuestionInitialData
);
});
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.modelQuestion.initializeComponent(
resultMap.modelQuestionInitialData
);
});
},
methods: {
backButtonAction() {
// route to move backwards
// route to move backwards
this.$router.navigate(
this.navigationScenarios.CLICKED_BACK,
this.$route
this.navigationScenarios.CLICKED_BACK,
this.$route
);
},
arePagePrerequisitesValid()
@ -86,26 +86,26 @@
},
},
computed: {
backButtonAccessibleText()
{
return this.getCmsContent(this.cmsWidgetName, "BackButtonAccessibleText")
}
backButtonAccessibleText()
{
return this.getCmsContent(this.cmsWidgetName, "BackButtonAccessibleText")
}
},
watch: {
selectedModel(model) {
this.mainStore.updateVehicleModel( model );
this.$router.navigate(
this.navigationScenarios.SELECTED_MODEL,
this.$route
);
},
selectedModel(model) {
this.mainStore.updateVehicleModel( model );
this.$router.navigate(
this.navigationScenarios.SELECTED_MODEL,
this.$route
);
},
},
components: {
modelQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
modelQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
},
};
</script>
};
</script>

View file

@ -4,7 +4,7 @@
</div>
<div class="nested-radio">
<div class="row my-2">
<div class="col mx-1">
<div class="col">
<buttonQuestion
v-model="selectedTint"
:answers="tintSelectionOptions"
@ -17,6 +17,7 @@
<div class="row my-2" aria-live="polite">
<div class="col">
<buttonQuestion
id="glass-part-question"
v-model="selectedPartNumber"
buttonTypeString="radio"
class="radioQuestion"
@ -25,8 +26,10 @@
textPosition="text-start"
:loaderEnabled="false"
isRequired
isSmallQuestionText
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
:validationRules="partValidationRules" />
:validationRules="partValidationRules"
/>
</div>
</div>
</buttonQuestion>
@ -179,25 +182,25 @@ export default {
return tintSourceObject.src;
},
// Check if only a single part is present for the tint and set the v-model if it is.
AutoSelect() {
if(this.partsForSelectedTint?.length > 0)
if (this.partsForSelectedTint?.length > 0)
{
// Check if only a single part is present for the tint and set the v-model if it is.
if (this.partsForSelectedTint?.length == 1) {
this.selectedPartNumber = { value: this.partsForSelectedTint[0].partNumber };
//select element with matching partNumber
this.$nextTick(() => {
document.querySelector('input[value=' + this.selectedPartNumber + ']').checked = true;
});
}
else{
else {
// If selected part isn't in the current list or it's null, select the first part
if(!this.selectedPartNumber || this.partsForSelectedTint.filter(x => x.partNumber == this.selectedPartNumber).length === 0)
{
this.selectedPartNumber = { value: this.partsForSelectedTint[0].partNumber };
}
}
//select element with matching partNumber
this.$nextTick(() => {
document.querySelector('input[value=' + this.selectedPartNumber + ']').checked = true;
});
}
},
@ -205,16 +208,10 @@ export default {
LoadPreselectedValues() {
this.$nextTick(() => {
// Populate button-question model-value if parts data already exists in store
if(this.modelValue)
if(this.modelValue !== undefined)
{
this.selectedTint = this.modelValue.color;
}
else{
// If one item in list, select it
if (this.tintSelectionOptions?.length == 1) {
this.selectedTint = this.tintSelectionOptions[0].value;
}
}
});
},
},
@ -242,4 +239,14 @@ export default {
color: $black;
font-weight: $font-weight-bold;
}
#glass-part-question {
span.fw-bold.w-100 {
margin-top: 0.5rem;
margin-bottom: 0;
}
div.col.radio-button-container {
padding-bottom: 0;
}
}
</style>

View file

@ -1,42 +1,53 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
<div class="page-container-grouped-styles vehicle-parts">
<siteHeader ref="siteHeader" cmsWidgetName="SiteHeaderWidget" />
<div class="fade-on-route-transition sub-container overflow-scroll px-5">
<vehicleBanner
class="mb-3"
ref="vehicleBanner"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader ref="siteSubHeader" cmsWidgetName="SiteSubHeaderWidget" />
<div class="prevent-squish my-5">
<div class="row">
<div class="col">
<alert
class="rounded border-0 shadow-sm"
alertClass="alert-warning"
cmsWidgetName="AlertWidget"
:isDismissible="false" />
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<vehicleBanner
class="mb-3"
ref="vehicleBanner"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader ref="siteSubHeader" cmsWidgetName="SiteSubHeaderWidget" />
<div class="prevent-squish my-5">
<div class="row">
<div class="col">
<alert
class="rounded border-0 shadow-sm"
alertClass="alert-warning"
cmsWidgetName="AlertWidget"
:isDismissible="false"
id="vehicle-parts-alert" />
</div>
</div>
</div>
<div v-for="(item, i) in PartsOrQuestions" :key="i">
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
<hr v-if="i > 0" />
<glassPartQuestion
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]"
:glassLocation="item.glassLocation"
:glassName="item.glassName"
:colorAnswers="item.colorAnswers"
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
</div>
<siteFooter
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
:isForwardActionDisabled="isForwardActionDisabled"
@backClicked="navigateBack"
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</div>
</div>
<div v-for="(item, i) in PartsOrQuestions" :key="i">
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
<hr v-if="i > 0" />
<glassPartQuestion
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]"
:glassLocation="item.glassLocation"
:glassName="item.glassName"
:colorAnswers="item.colorAnswers"
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
</div>
<siteFooter
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
:isForwardActionDisabled="isForwardActionDisabled"
@backClicked="navigateBack"
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</Form>
@ -79,151 +90,152 @@ export default {
// Glass Part Question dynamic component
Object.keys(vm.$refs)
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
.forEach((c) =>
vm.$refs[c][0].initializeComponent({
ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget,
FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget,
})
);
});
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
.forEach((c) =>
vm.$refs[c][0].initializeComponent({
ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget,
FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget,
})
);
});
},
data() {
return {
selectedGlassParts: {},
alertWidgetData: Object,
alreadyPopulatedPartsData: [],
};
},
computed: {
isForwardActionDisabled() {
return (
this.selectedGlassPartNumbers.length !== this.PartsFromApi.partsOrQuestions.length
);
},
data() {
return {
selectedGlassParts: {},
alertWidgetData: Object,
alreadyPopulatedPartsData: [],
};
selectedGlassPartNumbers() {
// Compile all selected parts from the page.
const numberArray = [];
for (let glassPart of Object.values(this.selectedGlassParts)) {
if (glassPart?.partNumber) {
numberArray.push(glassPart.partNumber);
}
}
return numberArray;
},
computed: {
isForwardActionDisabled() {
return (
this.selectedGlassPartNumbers.length !== this.PartsFromApi.partsOrQuestions.length
);
},
selectedGlassPartNumbers() {
// Compile all selected parts from the page.
const numberArray = [];
for (let glassPart of Object.values(this.selectedGlassParts)) {
if (glassPart?.partNumber) {
numberArray.push(glassPart.partNumber);
}
}
return numberArray;
},
PartsOrQuestions() {
const partsData = this.PartsFromApi;
PartsOrQuestions() {
const partsData = this.PartsFromApi;
// Map API result data, to vehicle-parts data structure
const mappedData = partsData.partsOrQuestions.map((g) => {
return {
glassName: g.glassName,
glassLocation: g.glassLocation,
colorAnswers: g.parts?.reduce((arr, p) => {
arr.push({
ColorAnswerText: p.color,
FeatureAnswers: [
{
FeatureAnswerText:
p.description === "" ? p.color : p.description,
PartNumber: p.partNumber,
},
],
});
return arr;
}, []),
};
});
return mappedData;
},
PartsFromApi() {
return this.mainStore.pageData(issPageValues.VEHICLE_PARTS);
},
RefPrefix() {
return "partQuestion";
},
},
methods: {
arePagePrerequisitesValid() {
// Check if isRepair is populated and if the pageData we need is here (Parts data)
return (
this.mainStore.damage.isRepair != null &&
this.mainStore.pageData(issPageValues.VEHICLE_PARTS) &&
Object.keys(this.mainStore.pageData(issPageValues.VEHICLE_PARTS)).length !== 0
);
},
async forwardButtonAction() {
const matchedParts = [];
// Match them to the parts from the API.
for (let [key, value] of Object.entries(this.PartsFromApi.partsOrQuestions)) {
for (let [partKey, partValue] of Object.entries(value.parts)) {
const currentPart = this.PartsFromApi.partsOrQuestions[key].parts[partKey];
const isMatched = this.selectedGlassPartNumbers.some(
(p) => p === currentPart.partNumber
);
if (isMatched) {
matchedParts.push({
glassLocation: value.glassLocation,
glassName: value.glassName,
parts: [currentPart],
});
}
}
}
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
if (this.isForwardActionDisabled) {
this.$refs.siteFooter.removeLoader();
throw new Error("Could not match any parts to the selected parts");
}
await this.mainStore.resetMoldingAndCapabilityQuestionAnswersIfNeeded(matchedParts);
this.navigateForward(matchedParts, null);
},
LoadInitialPartsData() {
const partsData = this.PartsFromApi;
this.alreadyPopulatedPartsData =
this.mainStore.lineItems.glassParts === null
? []
: this.mainStore.lineItems.glassParts;
partsData.partsOrQuestions.map((g) => {
// If the part is already populated, use the value from the store and populate the v-model.
Object.keys(this.alreadyPopulatedPartsData).forEach((key) => {
const partNumber = this.alreadyPopulatedPartsData[key].partNumber;
g.parts.forEach((p) => {
if (p.partNumber === partNumber) {
this.selectedGlassParts[g.glassLocation + "-" + g.glassName] = p;
}
// Map API result data, to vehicle-parts data structure
const mappedData = partsData.partsOrQuestions.map((g) => {
return {
glassName: g.glassName,
glassLocation: g.glassLocation,
colorAnswers: g.parts?.reduce((arr, p) => {
arr.push({
ColorAnswerText: p.color,
FeatureAnswers: [
{
FeatureAnswerText:
p.description === "" ? p.color : p.description,
PartNumber: p.partNumber,
},
],
});
return arr;
}, []),
};
});
return mappedData;
},
PartsFromApi() {
return this.mainStore.pageData(issPageValues.VEHICLE_PARTS);
},
RefPrefix() {
return "partQuestion";
},
},
methods: {
arePagePrerequisitesValid() {
// Check if isRepair is populated and if the pageData we need is here (Parts data)
return (
this.mainStore.damage.isRepair != null &&
this.mainStore.pageData(issPageValues.VEHICLE_PARTS) &&
Object.keys(this.mainStore.pageData(issPageValues.VEHICLE_PARTS)).length !== 0
);
},
async forwardButtonAction() {
const matchedParts = [];
// Match them to the parts from the API.
for (let [key, value] of Object.entries(this.PartsFromApi.partsOrQuestions)) {
for (let [partKey, partValue] of Object.entries(value.parts)) {
const currentPart = this.PartsFromApi.partsOrQuestions[key].parts[partKey];
const isMatched = this.selectedGlassPartNumbers.some(
(p) => p === currentPart.partNumber
);
if (isMatched) {
matchedParts.push({
glassLocation: value.glassLocation,
glassName: value.glassName,
parts: [currentPart],
});
}
}
}
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
if (this.isForwardActionDisabled) {
this.$refs.siteFooter.removeLoader();
throw new Error("Could not match any parts to the selected parts");
}
await this.mainStore.resetMoldingAndCapabilityQuestionAnswersIfNeeded(matchedParts);
this.navigateForward(matchedParts, null);
},
LoadInitialPartsData() {
const partsData = this.PartsFromApi;
this.alreadyPopulatedPartsData =
this.mainStore.lineItems.glassParts === null
? []
: this.mainStore.lineItems.glassParts;
partsData.partsOrQuestions.map((g) => {
// If the part is already populated, use the value from the store and populate the v-model.
Object.keys(this.alreadyPopulatedPartsData).forEach((key) => {
const partNumber = this.alreadyPopulatedPartsData[key].partNumber;
g.parts.forEach((p) => {
if (p.partNumber === partNumber) {
this.selectedGlassParts[g.glassLocation + "-" + g.glassName] = p;
}
});
});
},
},
mounted() {
this.LoadInitialPartsData();
},
components: {
Form,
glassPartQuestion,
siteHeader,
vehicleBanner,
siteSubHeader,
siteFooter,
alert,
});
},
},
mounted() {
this.LoadInitialPartsData();
},
components: {
Form,
glassPartQuestion,
siteHeader,
vehicleBanner,
siteSubHeader,
siteFooter,
alert,
},
};
</script>
<style lang="scss">
.overflow-scroll {
height: calc(100% - 180px);
overflow-x: hidden !important;
}
</style>
#vehicle-parts-alert {
.alert-heading {
margin-top: 0.25rem !important;
}
}
</style>

View file

@ -1,22 +1,20 @@
<template>
<div class="page-container-grouped-styles">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" class="mb-3" displayGenericVehicleImage />
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
:hasBackButton="true"
:backButtonAccessibleText="backButtonAccessibleText"
@click-event="backButtonAction" />
<div class="fade-on-route-transition">
<styleQuestion
v-model="selectedStyle"
ref="styleQuestion"
cmsWidgetName="VehicleStyleQuestion" />
<div class="page-container-grouped-styles position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" class="mb-3" displayGenericVehicleImage />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" :hasBackButton="true" :backButtonAccessibleText="backButtonAccessibleText" @click-event="backButtonAction" />
<styleQuestion v-model="selectedStyle" ref="styleQuestion" cmsWidgetName="VehicleStyleQuestion" class="px-4" />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" @back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</div>
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
@back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>

View file

@ -1,101 +1,101 @@
<template>
<div class="page-container-grouped-styles">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mb-3" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<div class="fade-on-route-transition">
<yearQuestion
class="fade-on-route-transition"
v-model="selectedYear"
ref="yearQuestion"
cmsWidgetName="VehicleYearQuestion"
/>
</div>
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
@back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
<div class="page-container-grouped-styles position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mb-3" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<yearQuestion class="px-4" v-model="selectedYear" ref="yearQuestion" cmsWidgetName="VehicleYearQuestion" />
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter" @back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
</template>
<script>
// Components
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteFooter from "@/iss-components/site-footer/site-footer";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
<script>
// Components
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
import siteHeader from "@/iss-components/site-header/site-header";
import siteFooter from "@/iss-components/site-footer/site-footer";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
export default {
export default {
name: "vehicle-year",
data() {
return {
selectedYear: null,
shouldHideForwardButton: true
};
return {
selectedYear: null,
shouldHideForwardButton: true
};
},
computed: {},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const yearQuestionInitialDataPromise = yearQuestion.methods.loadInitialData();
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const yearQuestionInitialDataPromise = yearQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "yearQuestionInitialData",
promise: yearQuestionInitialDataPromise,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "yearQuestionInitialData",
promise: yearQuestionInitialDataPromise,
},
];
let resultMap = await settleAllPromises(promiseResultMap);
let resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.yearQuestion.initializeComponent(
resultMap.yearQuestionInitialData
);
});
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.yearQuestion.initializeComponent(
resultMap.yearQuestionInitialData
);
});
},
watch: {
selectedYear(year) {
const parsedYear = parseInt(year);
this.mainStore.updateVehicleYear( parsedYear );
selectedYear(year) {
const parsedYear = parseInt(year);
this.mainStore.updateVehicleYear( parsedYear );
this.$router.navigate(
this.navigationScenarios.SELECTED_YEAR,
this.$route
);
},
this.$router.navigate(
this.navigationScenarios.SELECTED_YEAR,
this.$route
);
},
},
methods: {
arePagePrerequisitesValid() {
return true;
},
backButtonAction() {
arePagePrerequisitesValid() {
return true;
},
backButtonAction() {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
},
},
components: {
yearQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
yearQuestion,
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter
},
};
</script>
};
</script>

View file

@ -1,46 +1,27 @@
<template>
<Form
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
v-slot="{ meta }"
>
<div class="page-container-grouped-styles ">
<siteHeader
cmsWidgetName="SiteHeaderWidget"
/>
<div class="px-4 overflow-scroll ">
<div class="fade-on-route-transition sub-container px-2 mt-5">
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
/>
<vinLookupAlerts
:activeAlertType="activeVehicleLookupAlertType"
/>
<vinQuestion
v-model="vin"
:mask="vinMask"
:isDisabled="vinPopulatedOnPageLoad"
/>
<vinLocationInformation />
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="container-fluid pb-2">
<div class="row px-3">
<div class="col">
<div class="select-car-form rounded">
<vehicleBanner class="mb-3" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<vinLookupAlerts class="mt-5" :activeAlertType="activeVehicleLookupAlertType" />
<vinQuestion v-model="vin" :mask="vinMask" :isDisabled="vinPopulatedOnPageLoad" textPosition="left" />
<vinLocationInformation />
<siteFooter cmsWidgetName="SiteFooterWidget" :isForwardActionDisabled="!meta.valid" @backClicked="backButtonAction" @forwardClicked="forwardButtonAction" ref="siteFooter" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Form>
</Form>
</template>
<script>
// Import Supporting Files
@ -80,25 +61,25 @@ export default {
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
return {
activeVehicleLookupAlertType: null,
needToLookupVehicle: true,
vehicleFromLookup: null,
vin: this.getVinFromStore(),
forwardButtonCarStyle:"",
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
};
},
provide() {
return {
vehicleFromLookup: computed(() => this.vehicleFromLookup),
};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
return { mainStore };
},
data() {
return {
activeVehicleLookupAlertType: null,
needToLookupVehicle: true,
vehicleFromLookup: null,
vin: this.getVinFromStore(),
forwardButtonCarStyle:"",
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
};
},
provide() {
return {
vehicleFromLookup: computed(() => this.vehicleFromLookup),
};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
@ -110,51 +91,51 @@ export default {
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
computed: {
isCarIdDifferentFromTheStore() {
return (
this.vehicleFromLookup !== null
&& this.vehicleFromLookup.carId !== this.mainStore.vehicle.carId
);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
isTwoIdenticalYMMVehicleFound(){
const vinYmmFound = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return(vinYmmFound.toLowerCase()==vinYmmExpected.toLowerCase());
computed: {
isCarIdDifferentFromTheStore() {
return (
this.vehicleFromLookup !== null
&& this.vehicleFromLookup.carId !== this.mainStore.vehicle.carId
);
},
isTwoIdenticalYMMVehicleFound(){
const vinYmmFound = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return(vinYmmFound.toLowerCase()==vinYmmExpected.toLowerCase());
},
vinMask() {
if (this.vinPopulatedOnPageLoad) {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.PERFECT_MATCH;
this.needToLookupVehicle = false;
const lastSixChars = this.vin.substring(11, this.vin.length);
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
} else {
return "XXXXXXXXXXXXXXXXX";
}
},
},
vinMask() {
if (this.vinPopulatedOnPageLoad) {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.PERFECT_MATCH;
this.needToLookupVehicle = false;
const lastSixChars = this.vin.substring(11, this.vin.length);
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
} else {
return "XXXXXXXXXXXXXXXXX";
}
},
},
methods: {
arePagePrerequisiteValid() {
return true;
},
getVinFromStore() {
return this.mainStore.vehicle.vin;
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
// NOTE: If form is not valid, this method is not called when 'Continue' button is clicked
async forwardButtonAction() {
this.resetActiveAlert();
// Temp solution to reset the 'disabled' style on the Continue button
this.$refs.siteFooter.enableForwardAction();
methods: {
arePagePrerequisiteValid() {
return true;
},
getVinFromStore() {
return this.mainStore.vehicle.vin;
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
// NOTE: If form is not valid, this method is not called when 'Continue' button is clicked
async forwardButtonAction() {
this.resetActiveAlert();
// Temp solution to reset the 'disabled' style on the Continue button
this.$refs.siteFooter.enableForwardAction();
if (this.needToLookupVehicle) {
const vehicleLookupResponse = await this.lookupVehicleByVin(this.vin);
@ -174,18 +155,18 @@ export default {
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, { vin: this.vin });
}
if (this.needToLookupVehicle && this.isCarIdDifferentFromTheStore) {
if(this.isTwoIdenticalYMMVehicleFound){
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.TWO_IDENTICAL_YMM_MATCHED;
this.forwardButtonCarStyle = this.vehicleFromLookup.style;
}
else{
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NOT_MATCHED;
}
const vehicleYearMakeModelStyle = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model} ${this.forwardButtonCarStyle}`;
this.$refs.siteFooter.updateButtonText(`Continue with ${vehicleYearMakeModelStyle}`);
this.$refs.siteFooter.removeLoader();
if (this.needToLookupVehicle && this.isCarIdDifferentFromTheStore) {
if(this.isTwoIdenticalYMMVehicleFound){
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.TWO_IDENTICAL_YMM_MATCHED;
this.forwardButtonCarStyle = this.vehicleFromLookup.style;
}
else{
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NOT_MATCHED;
}
const vehicleYearMakeModelStyle = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model} ${this.forwardButtonCarStyle}`;
this.$refs.siteFooter.updateButtonText(`Continue with ${vehicleYearMakeModelStyle}`);
this.$refs.siteFooter.removeLoader();
this.needToLookupVehicle = false;
@ -212,18 +193,18 @@ export default {
return;
}
// save vehicle to store if it hasn't already been saved
if (!this.vinPopulatedOnPageLoad) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
}
// save vehicle to store if it hasn't already been saved
if (!this.vinPopulatedOnPageLoad) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
}
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
if (partsOrQuestionsResponse.error) {
// To Do: Need requirement on what to do here
console.error('Error on retrieving PartsOrQuestions');
this.$refs.siteFooter.removeLoader();
return;
}
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
if (partsOrQuestionsResponse.error) {
// To Do: Need requirement on what to do here
console.error('Error on retrieving PartsOrQuestions');
this.$refs.siteFooter.removeLoader();
return;
}
// Comes from vehicleQuestionsMixin.navigateForward()
await this.navigateForward(partsOrQuestionsResponse.data.partsOrQuestions, this);
@ -273,11 +254,3 @@ export default {
},
};
</script>
<style>
.overflow-scroll {
height: calc(100% - 180px);
overflow-X: hidden !important;
}
</style>

View file

@ -1,116 +1,115 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles welcome">
<siteHeader cmsWidgetName="SiteHeaderWidget"/>
<div class="fade-on-route-transition overflow-scroll container">
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget"/>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
inputId="policyNumberField"
cmsWidgetName="PolicyNumberQuestion"
v-model="welcomePageModel.policyNumber"
isRequired
ref="policyNumber"
disableAutoFill
validationRules="policy-number-required" />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
type="date"
cmsWidgetName="DateOfLossQuestion"
v-model="welcomePageModel.dateOfLoss"
inputId="dateOfLossField"
isRequired
ref="dateOfLoss"
disableAutoFill
:max="new Date().toJSON().slice(0,10)"
:min="'1972-12-01'"
validationRules="loss-date-required"
/>
</div>
</div>
<div class="row px-5">
<div class="col px-0">
<textBlock cmsWidgetName="DamageDateEstimateWidget" typeStyle="small" class="mt-2" />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<dropdownQuestion
cmsWidgetName="DamageCauseQuestion"
v-model="welcomePageModel.damageCause"
ref="damageCause"
inputId="damageCauseQuestionField"
:options="DamageCauseOptions"
disableAutoFill
validationRules="damage-option-required"
placeHolderText="Select an option"
id="welcomeDropdown"
/>
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
inputId="phoneNumberField"
cmsWidgetName="PhoneNumberQuestion"
v-model="welcomePageModel.phoneNumber"
validationRules="phone-number-required|phone-number-format"
isRequired
ref="phoneNumber"
mask="###-###-####"
disableAutoFill />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
inputId="emailField"
cmsWidgetName="EmailAddressQuestion"
v-model="welcomePageModel.email"
ref="email"
validationRules="email-address-required|email-address-format"
isRequired
disableAutoFill />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
inputId="damageCityField"
cmsWidgetName="DamageCityQuestion"
v-model="welcomePageModel.damageCity"
isRequired
ref="damageCity"
disableAutoFill
v-if="this.displayDamageCityQuestion"
validationRules="loss-city-required" />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<dropdownQuestion
cmsWidgetName="DamageStateQuestion"
v-model="welcomePageModel.damageState"
ref="state"
inputId="8fdf9dc2e13e430eb57529499dceb3eb"
:options="stateOptions"
validationRules="loss-state-required"
isRequired
disableAutoFill
v-if="this.displayDamageStateQuestion"
placeHolderText="Select an option"
id="welcomeDropdown"
/>
</div>
</div>
<div class="row mt-4">
<buttonQuestion
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }" >
<div class="page-container-grouped-styles welcome">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget"/>
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget"/>
<div class="container-fluid pb-2">
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
inputId="policyNumberField"
cmsWidgetName="PolicyNumberQuestion"
v-model="welcomePageModel.policyNumber"
isRequired
ref="policyNumber"
disableAutoFill
validationRules="policy-number-required" />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
type="date"
cmsWidgetName="DateOfLossQuestion"
v-model="welcomePageModel.dateOfLoss"
inputId="dateOfLossField"
isRequired
ref="dateOfLoss"
disableAutoFill
:max="new Date().toJSON().slice(0,10)"
:min="'1972-12-01'"
validationRules="loss-date-required"
/>
</div>
</div>
<div class="row px-5">
<div class="col px-0">
<textBlock cmsWidgetName="DamageDateEstimateWidget" typeStyle="small" class="mt-2" />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<dropdownQuestion
cmsWidgetName="DamageCauseQuestion"
v-model="welcomePageModel.damageCause"
ref="damageCause"
inputId="damageCauseQuestionField"
:options="DamageCauseOptions"
disableAutoFill
validationRules="damage-option-required"
placeHolderText="Select an option"
id="welcomeDropdown"
/>
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
inputId="phoneNumberField"
cmsWidgetName="PhoneNumberQuestion"
v-model="welcomePageModel.phoneNumber"
validationRules="phone-number-required|phone-number-format"
isRequired
ref="phoneNumber"
mask="###-###-####"
disableAutoFill />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
inputId="emailField"
cmsWidgetName="EmailAddressQuestion"
v-model="welcomePageModel.email"
ref="email"
validationRules="email-address-required|email-address-format"
isRequired
disableAutoFill />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<textboxQuestion
inputId="damageCityField"
cmsWidgetName="DamageCityQuestion"
v-model="welcomePageModel.damageCity"
isRequired
ref="damageCity"
disableAutoFill
v-if="this.displayDamageCityQuestion"
validationRules="loss-city-required" />
</div>
</div>
<div class="row mt-4 px-3">
<div class="col">
<dropdownQuestion
cmsWidgetName="DamageStateQuestion"
v-model="welcomePageModel.damageState"
ref="state"
inputId="8fdf9dc2e13e430eb57529499dceb3eb"
:options="stateOptions"
validationRules="loss-state-required"
isRequired
disableAutoFill
v-if="this.displayDamageStateQuestion"
placeHolderText="Select an option"
id="welcomeDropdown"
/>
</div>
</div>
<div class="row mt-4">
<buttonQuestion
class="px-0"
cmsWidgetName="GlassOnlyQuestion"
v-model="welcomePageModel.isDamageGlassOnly"
@ -120,240 +119,236 @@
buttonTypeString="listButtonHorizontal"
validationRules="damage-option-required"
isRequired
isSmallQuestionLabelText
ref="glassOnlyDamage"
v-if="this.displayGlassOnlyQuestion"
disableAutoFill/>
</div>
<div class="row mt-4 position-sticky top-100" id="welcomeFooter">
<div class="col">
<site-footer
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
</div>
<div class="row mt-4 position-sticky top-100" id="welcomeFooter">
<div class="col">
<site-footer
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</div>
</div>
</div>
</Form>
</Form>
</template>
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
import siteFooter from "@/iss-components/site-footer/site-footer";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
import buttonQuestion from "@/digital-components/button-question/button-question";
import dropdownQuestion from "@/digital-components/dropdown-question/dropdown-question";
import textBlock from "@/digital-components/text-block/text-block";
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
import siteFooter from "@/iss-components/site-footer/site-footer";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
import buttonQuestion from "@/digital-components/button-question/button-question";
import dropdownQuestion from "@/digital-components/dropdown-question/dropdown-question";
import textBlock from "@/digital-components/text-block/text-block";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { Form, defineRule } from "vee-validate";
import { required, regex } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { Form, defineRule } from "vee-validate";
import { required, regex } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';
//define validation rules
defineRule("loss-date-required", required(errorMessages.LOSS_DATE_REQUIRED));
defineRule("loss-cause-required", required(errorMessages.LOSS_CAUSE_REQUIRED));
defineRule("policy-number-required", required(errorMessages.POLICY_NUMBER_REQUIRED));
defineRule("loss-date-required", required(errorMessages.LOSS_DATE_REQUIRED));
defineRule("loss-state-required", required(errorMessages.LOSS_STATE_REQUIRED));
defineRule("loss-city-required", required(errorMessages.LOSS_CITY_REQUIRED));
defineRule("phone-number-required", required(errorMessages.PHONE_NUMBER_FORMAT));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule("damage-option-required", required(errorMessages.DAMAGE_OPTION_REQUIRED));
//define validation rules
defineRule("loss-date-required", required(errorMessages.LOSS_DATE_REQUIRED));
defineRule("loss-cause-required", required(errorMessages.LOSS_CAUSE_REQUIRED));
defineRule("policy-number-required", required(errorMessages.POLICY_NUMBER_REQUIRED));
defineRule("loss-date-required", required(errorMessages.LOSS_DATE_REQUIRED));
defineRule("loss-state-required", required(errorMessages.LOSS_STATE_REQUIRED));
defineRule("loss-city-required", required(errorMessages.LOSS_CITY_REQUIRED));
defineRule("phone-number-required", required(errorMessages.PHONE_NUMBER_FORMAT));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule("damage-option-required", required(errorMessages.DAMAGE_OPTION_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("phone-number-format",
regex(
/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/,
errorMessages.PHONE_NUMBER_FORMAT
)
);
defineRule("phone-number-format",
regex(
/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/,
errorMessages.PHONE_NUMBER_FORMAT
)
);
export default {
name: "welcome-page",
mixins: [BaseFormMixin],
data() {
return {
welcomePageModel: this.getWelcomePageModelFromStore()
};
},
setup() {
const mainStore = useMainStore();
export default {
name: "welcome-page",
mixins: [BaseFormMixin],
data() {
return {
welcomePageModel: this.getWelcomePageModelFromStore()
};
},
setup() {
const mainStore = useMainStore();
// Set order account number from the issConfig.
mainStore.order.accountNumber = mainStore.issConfig.accountNumber;
// Set order account number from the issConfig.
mainStore.order.accountNumber = mainStore.issConfig.accountNumber;
return { mainStore };
},
async beforeRouteEnter(to, from, next)
{
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
return { mainStore };
},
async beforeRouteEnter(to, from, next)
{
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
},
];
//use resultMap to populate layout content.
let resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
methods:
{
async forwardButtonAction() {
this.mainStore.updatePolicyData(this.welcomePageModel);
return this.navigateForward();
},
//use resultMap to populate layout content.
let resultMap = await settleAllPromises(promiseResultMap);
navigateForward() {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WELCOME_PAGE,
this.$route
);
},
getWelcomePageModelFromStore() {
return {
policyNumber : this.mainStore.order.policy.policyNumber,
dateOfLoss : this.mainStore.order.policy.dateOfLoss,
damageCause : this.mainStore.order.policy.damageCause,
damageState : this.mainStore.order.policy.damageState,
damageCity : this.mainStore.order.policy.damageCity,
isDamageGlassOnly : this.mainStore.order.policy.isDamageGlassOnly,
phoneNumber : this.mainStore.order.customer.phoneNumber,
email : this.mainStore.order.customer.emailAddress,
}
},
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
methods:
{
async forwardButtonAction() {
this.mainStore.updatePolicyData(this.welcomePageModel);
return this.navigateForward();
},
computed:{
DamageCauseOptions() {
const damageCauseAnswers = this.getCmsContent("DamageCauseQuestion", "Answers");
const damageCauseAnswersObj ={};
if(damageCauseAnswers)
{
for (let answer of Object.values(damageCauseAnswers)) {
if (answer?.Name) {
damageCauseAnswersObj[answer.Name] = answer.Name;
}
}
}
return damageCauseAnswersObj;
},
DamageGlassOnlyOptions()
{
return this.getCmsContent("GlassOnlyQuestion", "Answers");
},
DamageGlassOnlyQuestion()
{
return this.getCmsContent("GlassOnlyQuestion", "QuestionText");
},
stateOptions: {
get: function () {
return {
AL: "Alabama",
AK: "Alaska",
AZ: "Arizona",
AR: "Arkansas",
CA: "California",
CO: "Colorado",
CT: "Connecticut",
DE: "Delaware",
DC: "District Of Columbia",
FL: "Florida",
GA: "Georgia",
HI: "Hawaii",
ID: "Idaho",
IL: "Illinois",
IN: "Indiana",
IA: "Iowa",
KS: "Kansas",
KY: "Kentucky",
LA: "Louisiana",
ME: "Maine",
MD: "Maryland",
MA: "Massachusetts",
MI: "Michigan",
MN: "Minnesota",
MS: "Mississippi",
MO: "Missouri",
MT: "Montana",
NE: "Nebraska",
NV: "Nevada",
NH: "New Hampshire",
NJ: "New Jersey",
NM: "New Mexico",
NY: "New York",
NC: "North Carolina",
ND: "North Dakota",
OH: "Ohio",
OK: "Oklahoma",
OR: "Oregon",
PA: "Pennsylvania",
RI: "Rhode Island",
SC: "South Carolina",
SD: "South Dakota",
TN: "Tennessee",
TX: "Texas",
UT: "Utah",
VT: "Vermont",
VA: "Virginia",
WA: "Washington",
WV: "West Virginia",
WI: "Wisconsin",
WY: "Wyoming",
};
},
},
displayDamageCityQuestion(){
return !!this.getCmsContent("DamageCityQuestion","QuestionText");
},
displayDamageStateQuestion(){
return !!this.getCmsContent("DamageStateQuestion","QuestionText");
},
displayGlassOnlyQuestion(){
return !!this.getCmsContent("GlassOnlyQuestion","QuestionText");
navigateForward() {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WELCOME_PAGE,
this.$route
);
},
getWelcomePageModelFromStore() {
return {
policyNumber : this.mainStore.order.policy.policyNumber,
dateOfLoss : this.mainStore.order.policy.dateOfLoss,
damageCause : this.mainStore.order.policy.damageCause,
damageState : this.mainStore.order.policy.damageState,
damageCity : this.mainStore.order.policy.damageCity,
isDamageGlassOnly : this.mainStore.order.policy.isDamageGlassOnly,
phoneNumber : this.mainStore.order.customer.phoneNumber,
email : this.mainStore.order.customer.emailAddress,
}
},
components: {
siteHeader,
siteSubHeader,
buttonQuestion,
textboxQuestion,
dropdownQuestion,
siteFooter,
textBlock,
Form,
},
computed:{
DamageCauseOptions() {
const damageCauseAnswers = this.getCmsContent("DamageCauseQuestion", "Answers");
const damageCauseAnswersObj ={};
if(damageCauseAnswers)
{
for (let answer of Object.values(damageCauseAnswers)) {
if (answer?.Name) {
damageCauseAnswersObj[answer.Name] = answer.Name;
}
}
}
return damageCauseAnswersObj;
},
}
DamageGlassOnlyOptions()
{
return this.getCmsContent("GlassOnlyQuestion", "Answers");
},
DamageGlassOnlyQuestion()
{
return this.getCmsContent("GlassOnlyQuestion", "QuestionText");
},
stateOptions: {
get: function () {
return {
AL: "Alabama",
AK: "Alaska",
AZ: "Arizona",
AR: "Arkansas",
CA: "California",
CO: "Colorado",
CT: "Connecticut",
DE: "Delaware",
DC: "District Of Columbia",
FL: "Florida",
GA: "Georgia",
HI: "Hawaii",
ID: "Idaho",
IL: "Illinois",
IN: "Indiana",
IA: "Iowa",
KS: "Kansas",
KY: "Kentucky",
LA: "Louisiana",
ME: "Maine",
MD: "Maryland",
MA: "Massachusetts",
MI: "Michigan",
MN: "Minnesota",
MS: "Mississippi",
MO: "Missouri",
MT: "Montana",
NE: "Nebraska",
NV: "Nevada",
NH: "New Hampshire",
NJ: "New Jersey",
NM: "New Mexico",
NY: "New York",
NC: "North Carolina",
ND: "North Dakota",
OH: "Ohio",
OK: "Oklahoma",
OR: "Oregon",
PA: "Pennsylvania",
RI: "Rhode Island",
SC: "South Carolina",
SD: "South Dakota",
TN: "Tennessee",
TX: "Texas",
UT: "Utah",
VT: "Vermont",
VA: "Virginia",
WA: "Washington",
WV: "West Virginia",
WI: "Wisconsin",
WY: "Wyoming",
};
},
},
displayDamageCityQuestion(){
return !!this.getCmsContent("DamageCityQuestion","QuestionText");
},
displayDamageStateQuestion(){
return !!this.getCmsContent("DamageStateQuestion","QuestionText");
},
displayGlassOnlyQuestion(){
return !!this.getCmsContent("GlassOnlyQuestion","QuestionText");
}
},
components: {
siteHeader,
siteSubHeader,
buttonQuestion,
textboxQuestion,
dropdownQuestion,
siteFooter,
textBlock,
Form,
},
}
</script>
<style lang="scss">
.overflow-scroll {
height: calc(100% - 165px);
overflow-X: hidden !important;
}
.my-2
{
.my-2 {
margin-bottom: 0rem !important;
}
@-moz-document url-prefix() {

View file

@ -440,6 +440,16 @@ const routingTable = function(store) {
},
],
},
{
issPageValue: issPageValues.SERVICE_LOCATION,
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
destinationIssPageValue: issPageValues.PROVIDER_PREFERENCE,
},
],
},
];
};

View file

@ -160,13 +160,6 @@ html {
font-weight: 500;
}
.vehicle-damage,
.vehicle-lookup {
.form-test-error {
margin: 0;
padding: 0 .75rem;
}
}
.form-test-invalid {
&.btn.btn-primary {

View file

@ -5,62 +5,62 @@ body {
background-color: #fff;
color: #4D5151;
.container-fluid {
max-width: 576px; //Remove once desktop app is complete
&.container-shadow {
box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.15); //Use instead of Bootstrap's helper
}
&.make-tall {
height: 100vh;
display: flex;
flex-direction: column;
}
.prevent-squish{
overflow-x: unset;
}
max-width: 576px; //Remove once desktop app is complete
&.container-shadow {
box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.15); //Use instead of Bootstrap's helper
}
&.make-tall {
height: 100vh;
display: flex;
flex-direction: column;
}
.prevent-squish{
overflow-x: unset;
}
}
.pointer {
cursor: pointer;
cursor: pointer;
}
.container,
.container-fluid {
overflow: hidden;
overflow: hidden;
}
.sub-container{
&.make-tall {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
overflow-x: hidden;
}
&.make-tall {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
overflow-x: hidden;
}
}
.sr-only {
position: absolute;
left: -10000px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
position: absolute;
left: -10000px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
}
.page-container-grouped-styles {
@extend .container-fluid, .shadow, .rounded-3, .p-0, .position-relative, .make-tall;
@extend .container-fluid, .shadow, .p-0, .position-relative, .make-tall;
}
//Footer modal backdrop adjustments for positioning
.modal-backdrop {
left: 50%;
transform: translateX(-50%);
max-width: 576px;
height: calc(100% - 72px);
left: 50%;
transform: translateX(-50%);
max-width: 576px;
height: calc(100% - 72px);
}
.modal-text {
display: inline;
color: $blue;
cursor: pointer;
text-decoration: underline;
// Scroll page when modal isn't open
.fade-on-route-transition {
height: calc(100% - 80px);
overflow: auto;
}
}
// Prevent scroll when modal is open
.modal-open {
.fade-on-route-transition {
overflow: hidden;
}
}
}

View file

@ -68,6 +68,9 @@ $orange: #fd7e14;
$teal: #20c997;
$cyan: #0dcaf0;
// Darker gray
$darker-gray: #525656;
// scss-docs-start colors-map
$colors: (
"blue": $blue,
@ -83,6 +86,7 @@ $colors: (
"white": $white,
"gray": $gray,
"gray-dark": $gray-500,
"darker-gray":$darker-gray,
);
// scss-docs-start theme-color-variables