Merge branch 'develop' into feature/Digital/SSR-226

This commit is contained in:
Jason Wheeler 2023-02-16 17:32:16 -05:00
commit 55fc7c66a9
23 changed files with 737 additions and 166 deletions

View file

@ -1,6 +1,6 @@
<template>
<div
class="text-block w-100 mt-2"
class="text-block w-100"
:class="[justifyText, typeStyle, fontWeight]"
v-html="this.TextBlockCopy"></div>
</template>
@ -25,12 +25,15 @@ export default {
<style lang="scss" scoped>
.text-block {
&.left {
display: flex;
justify-content: flex-start;
}
&.right {
display: flex;
justify-content: flex-end;
}
&.center {
display: flex;
justify-content: center;
}
&.bold {

View file

@ -2,7 +2,7 @@
<div :class="`page-container-grouped-styles questions-page`">
<loadingModal ref="loadingModal" />
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
<vehicleBanner class="mb-3" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall">
<alert

View file

@ -1,5 +1,5 @@
<template>
<div class="vehicle_banner mb-3 text-center">
<div class="vehicle_banner text-center">
<img
class="vehicle-image img-fluid"
:src="vehicleImageToDisplay"
@ -21,9 +21,9 @@ export default {
computed: {
vehicleImageToDisplay(){
if (this.displayGenericVehicleImage){
return this.genericVehicleImage;
return this.genericVehicleImage;
}
const imageUrl = this.mainStore.order.vehicle.imageUrl;
if (!imageUrl || imageUrl === "NULL"){
return this.getUnmatchedVehicleIcon();

View file

@ -8,6 +8,7 @@
<div class="page-container-grouped-styles">
<siteHeader cmsWidgetName="SiteHeaderWidget" ref="siteHeader" />
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
ref="vehicleBanner"
:displayGenericVehicleImage="false" />
@ -37,7 +38,7 @@
v-bind:isDismissible="false" />
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
<siteFooter
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
@ -116,7 +117,7 @@ export default {
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
attachCustomEvents() {
this.prependActionToMethod(this, this.forwardButtonAction, () => {
this.pushEventToGA(
this.$route.query[this.queryStrings.ISS_PAGE],
@ -125,7 +126,7 @@ export default {
true
);
});
},
async forwardButtonAction() {
@ -237,7 +238,7 @@ export default {
// display vehicle changed alert on that page.
if (
this.isCarIdDifferent &&
!this.isSelectedGlassAvailableForVehicle
!this.isSelectedGlassAvailableForVehicle
) {
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,

View file

@ -8,6 +8,7 @@
<div class="page-container-grouped-styles overflow-auto">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
@ -264,4 +265,4 @@ export default {
#multiple-vehicles-alert p {
margin-bottom: 0 !important; // Overrides extra margin-bottom on alert body text
}
</style>
</style>

View file

@ -11,6 +11,7 @@
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
class="mb-3"
/>
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
@ -50,11 +51,11 @@ export default {
siteHeader,
siteSubHeader,
Form,
vehicleBanner,
},
vehicleBanner,
},
data() {
return {};
},
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
@ -82,7 +83,7 @@ export default {
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {},
async forwardButtonAction() {},
resetDependentState() {},
},
};

View file

@ -11,13 +11,30 @@
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
class="mb-0"
/>
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
/>
<div class="fade-on-route-transition sub-container make-tall mt-5">
<p>Placeholder for coverage-statement page</p>
<div class="fade-on-route-transition sub-container make-tall">
<textBlock
cmsWidgetName="verifyingCoverageStatement"
typeStyle="h5"
justifyText="center"
class="mt-4 mb-4"
/>
<textBlock
cmsWidgetName="continueWithSchedulingCopy"
typeStyle="body"
class="mt-0"
/>
<textBlock
cmsWidgetName="whatHappensNextCopy"
class="mt-4 mb-2 fw-bold"
/>
<textBlock
cmsWidgetName="UnverifiedADASNextStepsWidget"
typeStyle="body"
/>
<a href="#!" data-bs-toggle="modal" data-bs-target="#RecalModal" aria-label="Modal window">Recalibration</a>
<modal cmsWidgetName="RecalModal" />
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ -30,9 +47,6 @@
</Form>
</template>
<script>
// Import Supporting Files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { settleAllPromises } from '@/helpers/layout-helper';
// Import Component
import baseFormMixin from '@/mixins/base-form-mixin';
@ -41,6 +55,12 @@ 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';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import textBlock from "@/digital-components/text-block/text-block";
import modal from "@/digital-components/modal/modal";
// Import Supporting Files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { settleAllPromises } from '@/helpers/layout-helper';
export default {
name: 'coverage-statement',
@ -50,11 +70,13 @@ export default {
siteHeader,
siteSubHeader,
Form,
vehicleBanner,
},
vehicleBanner,
textBlock,
modal,
},
data() {
return {};
},
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
@ -82,8 +104,17 @@ export default {
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {},
async forwardButtonAction() {},
resetDependentState() {},
},
};
</script>
<style lang="scss">
ol {
margin-left: -1rem;
li {
margin-bottom: .5rem;
}
}
</style>

View file

@ -1,11 +1,12 @@
<template>
<Form
<template>
<Form
@submit="onSubmit"
@invalid-submit="onInvalidSubmit"
v-slot="{ meta }">
<div class="page-container-grouped-styles overflow-auto">
<siteHeader cms-widget-name="SiteHeaderWidget" />
<vehicleBanner
class="mb-3"
cms-widget-name="VehicleBannerWidget"
:display-generic-vehicle-image="false" />
<siteSubHeader cms-widget-name="SiteSubHeaderWidget" />
@ -29,7 +30,7 @@
<textboxQuestion
cmsWidgetName="LicensePlateNumberQuestionWidget"
v-model="licensePlate"
isRequired
isRequired
disableAutoFill
id="license-plate-question-wrapper"
inputId="license-plate-question"
@ -97,17 +98,17 @@ export default {
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.setCmsContent(resultMap.cmsContent);
});
},
data() {
return {
activeVehicleLookupAlertType: null,
vehicleFromLookup: null,
licensePlate: null,
licensePlate: null,
licenseState: null,
displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false,
@ -118,7 +119,7 @@ export default {
};
},
methods: {
arePagePrerequisitesValid() {
arePagePrerequisitesValid() {
return this.mainStore.order.vehicle.carId !== null;
},
loadDefaultsFromStore() {
@ -162,7 +163,7 @@ export default {
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
};
// Vehicle found from VIN lookup
const vehicleFromLookup = resultMap.vinLookupResponse.vehicle;
@ -193,7 +194,7 @@ export default {
await useMainStore().saveRegistrationLicensePlateLookup(
{
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
vehicleInfo: Object.assign(vehicleFromLookup, {vin: vehicleFromLookup.vin }),
vehicleInfo: Object.assign(vinLookupResponse.data.vehicle, { vin: vinLookupResponse.data.vin }),
registrationInfo: {
licensePlate: this.licensePlate,
state: this.licenseState,

View file

@ -0,0 +1,388 @@
// Components
import moldingQuestions from "@/layouts/molding-questions/molding-questions";
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { useMainStore } from "@/store";
import baseMixin from "../../mixins/base-mixin";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { nextTick } from "vue";
// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
settleAllPromises: jest.fn(),
}));
// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
fetchCmsContentForPage: jest.fn(),
}));
const baseStoreGettersPageData = () => {
return {
partsOrQuestions: [
{
parts: [
{
childPartQuestions: [
{
questionSequence: 1,
questionText:
"Does the rubber seal around your windshield have a chrome strip running through it?",
answers: [
{
answerResult: "WKT D1106 C",
answerText: "Yes",
nextQuestionSequence: null,
},
{
answerResult: "WKT D1106 B",
answerText: "No",
nextQuestionSequence: null,
},
],
},
],
basePartNumber: "DW01105",
color: "Green Tint, Blue Shade",
requiresRecalibration: false,
recalibrationType: "",
canSafeliteRecalibrate: false,
requiresCapabilityQuestions: false,
childParts: null,
partNumber: "DW01105GBNN",
description: "solar",
partType: "WINDSHIELD",
},
],
partQuestions: [],
glassLocation: "Windshield",
glassName: "Single",
answerKey: "Windshield-Single",
answerData: null,
},
],
};
};
const baseStoreGettersDamage = () => {
return {
partsQuestionAnswers: [
{
glassLocation: "Windshield",
glassName: "Single",
result: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswer: "1|nextQuestion|3|Yes",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswer: "2|nextQuestion|3|Yes",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
},
],
};
};
useMainStore().pageData = baseStoreGettersPageData;
useMainStore().damage = baseStoreGettersDamage;
describe("moldingQuestions.vue", () => {
describe("method arePagePrerequisitesValid...", () => {
test("Should return true for valid page requisites if pageData exists", () => {
// Arrange
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBe(true);
wrapper.unmount();
});
test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => {
// Arrange
const { wrapper } = setupMocks({});
useMainStore().pageData = jest.fn(() => {
return undefined;
});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBeFalsy();
wrapper.unmount();
});
test("Should be at least one item in partsOrQuestions", () => {
// Arrange
useMainStore().pageData = jest.fn(() => {
return {
partsOrQuestions: [],
};
});
useMainStore().damage = baseStoreGettersDamage;
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBeFalsy();
wrapper.unmount();
});
});
describe("watch on selectedAnswers should be set up...", () => {
test("Should trigger handleAnswerUpdates if watched data changes", async () => {
// Arrange
useMainStore().pageData = baseStoreGettersPageData;
useMainStore().damage = baseStoreGettersDamage;
const { wrapper } = setupMocks({});
const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates");
// Act
wrapper.setData({
selectedAnswers: {
"Windshield-Single": {
answerResult: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswer: "1|nextQuestion|3|Yes",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswer: "2|nextQuestion|3|Yes",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
index: 0,
},
},
});
await nextTick();
//Assert
expect(spy).toHaveBeenCalled();
wrapper.unmount();
});
});
describe("forwardButtonAction", () => {
test("Should clear out answerData", () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: {
partsOrQuestions: [],
},
};
});
// Act
wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.questionsData[0].answerData).toEqual({});
wrapper.unmount();
});
test("Should save to pinia store", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
useMainStore().getPartsOrQuestions = jest.fn(() => {
return {
data: {
partsOrQuestions: [],
},
};
});
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(wrapper.vm.saveMoldingQuestionAnswers).toHaveBeenCalled;
wrapper.unmount();
});
test("Should call GET_PARTS_OR_QUESTIONS API", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
useMainStore().getPartsOrQuestions = jest.fn(() => {
return {
data: {
partsOrQuestions: [],
},
};
});
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(wrapper.vm.getPartsOrQuestions).toHaveBeenCalled;
wrapper.unmount();
});
test("Should trigger navigateForward", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
useMainStore().getPartsOrQuestions = jest.fn(() => {
return {
data: {
partsOrQuestions: [],
},
};
});
wrapper.vm.navigateForward = jest.fn();
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
wrapper.unmount();
});
});
});
function setupMocks({
mountOptionsMockData = {
router: {
navigate: jest.fn(),
},
actionList: [
{
actionName: "saveMoldingQuestionAnswers",
data: {},
},
{
actionName: "getPartsOrQuestions",
data: {},
},
],
route: {
query: {
issPage: "molding-questions",
},
},
data() {
return {
computedSwitcher: [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
],
};
},
questionsData: {
get() {
return this.computedSwitcher;
},
set(val) {
this.computedSwitcher = val;
},
},
},
}) {
useMainStore().getPartsOrQuestions = jest.fn(() => {
return {
data: {
partsOrQuestions: [],
}
};
});
const mountOptions = getMountOptions({
...mountOptionsMockData,
mixins: [baseMixin, vehicleQuestionsMixin],
});
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(moldingQuestions, mountOptions);
return { wrapper };
}

View file

@ -2,66 +2,54 @@
<Form
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
ref="theForm"
v-slot="{ meta }"
>
<div class="page-container-grouped-styles overflow-auto">
<siteHeader
cmsWidgetName="SiteHeaderWidget"
/>
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
/>
<div class="fade-on-route-transition sub-container make-tall mt-5">
<p>Placeholder for molding-questions page</p>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
</div>
</div>
<questionsPageLayout
isRequired
ref="questionsPageLayout"
:isMetaValid="meta.valid"
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
:questionsData="questionsData"
validationRules="questions-required"
v-model="selectedAnswers"
@forwardButtonAction="forwardButtonAction"
@back-click="navigateBack"
:index="currentGlassIndex"
id="molding-question-wrapper"
/>
</Form>
</template>
<script>
// Import Supporting Files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { settleAllPromises } from '@/helpers/layout-helper';
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { useMainStore } from "@/store";
import { issPageValues } from "@/router/router-constants/issPage-values";
import BaseFormMixin from '@/mixins/base-form-mixin.js';
// Import Component
import baseFormMixin from '@/mixins/base-form-mixin';
import { Form } 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';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import { Form } from "vee-validate";
import questionsPageLayout from "@/iss-components/questions-page-layout/questions-page-layout.vue";
// DEFINE VALIDATION RULES
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
export default {
name: 'molding-questions',
mixins: [baseFormMixin],
components: {
siteFooter,
siteHeader,
siteSubHeader,
Form,
vehicleBanner,
},
data() {
return {};
},
name: "molding-questions",
mixins: [BaseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
@ -72,18 +60,127 @@ export default {
vm.setCmsContent(resultMap.cmsContent);
});
},
data() {
return {
questionsData: [],
selectedAnswers: {},
currentGlassIndex: 0,
};
},
computed: {
AlertFewMoreQuestionsHeader() {
return this.getCmsContent(
"AdditionalPartsQuestionsAlert",
"HeadlineText"
);
},
AlertFewMoreQuestionsCopy() {
return this.getCmsContent("AdditionalPartsQuestionsAlert", "BodyText");
},
partsOrQuestionsData() {
return useMainStore().pageData(issPageValues.MOLDING_QUESTIONS)
.partsOrQuestions;
},
},
mounted() {
this.getInitialQuestionData();
},
methods: {
arePagePrerequisiteValid() {
return true;
arePagePrerequisitesValid() {
const moldingQuestionsFromPageData = useMainStore().pageData(
issPageValues.MOLDING_QUESTIONS
);
return (
// has childPartQuestions array and has glassName not null
moldingQuestionsFromPageData?.partsOrQuestions?.some(
(part) => part?.glassName
) &&
moldingQuestionsFromPageData.partsOrQuestions.some((glass) =>
glass.parts?.some((part) => part?.childPartQuestions?.length > 0)
)
);
},
backButtonAction() {
/**
* this.navigationScenarios comes from base-mixin
*/
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
getInitialQuestionData() {
// get any questions that were already answered
const alreadyAnsweredQuestions =
useMainStore().damage.moldingQuestionAnswers;
this.questionsData = this.partsOrQuestionsData
.filter((x) => x.parts[0].childPartQuestions.length)
.map((glass, index) => {
// NOTE: questions for property "questions" can differ between layouts
glass.questions = glass.parts[0].childPartQuestions;
glass.answerKey = glass.glassLocation + "-" + glass.glassName;
// reset selectedAnswers for this glass
this.selectedAnswers[glass.answerKey] = [];
const updatedGlass = this.setupInitialData(
glass,
index,
alreadyAnsweredQuestions
);
// Set up watch for each set of glass questions
this.$watch(
"selectedAnswers." + glass.answerKey,
(newValue) => {
if (newValue && Object.keys(newValue).length > 0) {
this.handleAnswerUpdates(
newValue,
glass.answerKey
);
}
},
{ deep: true }
);
return updatedGlass;
});
},
async forwardButtonAction() {},
resetDependentState() {},
async forwardButtonAction() {
const questionAnswersArray = this.questionsData.map((glass) => {
return {
glassLocation: glass.glassLocation,
glassName: glass.glassName,
partNum: glass.answerData.answerResult,
answeredQuestions: glass.answerData.answeredQuestions,
isSuppressedPart: glass.isSuppressedPart,
};
});
// clear out answerData for future page loads; must occur prior to store save
this.questionsData.forEach((glass) => {
glass.answerData = {};
});
// save to store as order.damage.moldingQuestionArrays (array)
await this.mainStore.saveMoldingQuestionAnswers(questionAnswersArray);
// get parts from the questionAnswers
let partsOrQuestions = this.partsOrQuestionsData;
for (let answer of questionAnswersArray) {
partsOrQuestions.find((partOrQuestion) => {
return (
partOrQuestion.glassLocation === answer.glassLocation &&
partOrQuestion.glassName === answer.glassName
);
}).parts[0].childParts = [
{
partNumber: answer.partNum,
},
];
}
this.navigateForward(partsOrQuestions, null);
},
},
components: {
Form,
questionsPageLayout,
},
};
</script>
<style lang="scss">
#molding-question-wrapper p.text-body.small {
margin-bottom: 0 !important; // Overrides extra margin-bottom on alert body text
}
#molding-question-wrapper .form-test-error {
margin-top: 0 !important; // Overrides extra margin-top on error message text
}
</style>

View file

@ -3,8 +3,8 @@
<div class="page-container-grouped-styles overflow-auto">
<div class="fade-on-route-transition">
<siteHeader cmsWidgetName="SiteHeaderWidget"/>
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget"/>
<addressQuestions ref="addressQuestions" v-model="customerQuestions.addressQuestions" includeStreetAddress2="true" />
<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
@ -141,4 +141,22 @@ export default {
{
margin-top: 20px;
}
#sub-header p {
font-size: 16px;
line-height: 26px;
color: #4D5151;
}
#address-questions-wrapper {
margin-top: 24px;
}
#address-questions-wrapper .alert.heading {
line-height: 24px;
}
#address-questions-wrapper .form-test-error {
line-height: 24px;
}
</style>

View file

@ -3,6 +3,7 @@
<div class="page-container-grouped-styles overflow-auto">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
@ -123,7 +124,7 @@ export default {
},
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
@ -138,7 +139,7 @@ export default {
selectedRearReplaceOptions: this.getRearReplaceOptionsFromStore(),
};
},
methods: {
methods: {
arePagePrerequisitesValid() {
if (this.mainStore.order.vehicle.carId) {
return true;
@ -306,8 +307,8 @@ export default {
return this.navigateForward();
},
navigateForward() {
if (this.mainStore.damage.isRepair) {
navigateForward() {
if (this.mainStore.damage.isRepair) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR,
this.$route
@ -326,7 +327,7 @@ export default {
this.$route
);
}
}
}
},
selectedGlassToReplace() {

View file

@ -8,6 +8,7 @@
cms-widget-name="SiteHeaderWidget"
/>
<VehicleBanner
class="mb-3"
cms-widget-name="VehicleBannerWidget"
:display-generic-vehicle-image="false"
/>

View file

@ -3,21 +3,21 @@
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true"/>
<siteSubHeader
<vehicleBanner class="mb-3" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true"/>
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
:hasBackButton="true"
@click-event="backButtonAction"
/>
<div class="fade-on-route-transition">
<makeQuestion
<makeQuestion
class="fade-on-route-transition"
v-model="selectedMake"
ref="makeQuestion"
cmsWidgetName="VehicleMakeQuestion"
v-model="selectedMake"
ref="makeQuestion"
cmsWidgetName="VehicleMakeQuestion"
/>
</div>
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
@back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
@ -45,11 +45,11 @@
};
},
async beforeRouteEnter(to, from, next) {
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const makeQuestionInitialDataPromise = makeQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
@ -61,9 +61,9 @@
promise: makeQuestionInitialDataPromise,
},
];
let resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
@ -95,12 +95,12 @@
},
watch: {
selectedMake(make) {
this.mainStore.updateVehicleMake( make );
this.mainStore.updateVehicleMake( make );
this.$router.navigate(
this.navigationScenarios.SELECTED_MAKE,
this.$route
);
},
}
}
};
</script>
</script>

View file

@ -3,7 +3,7 @@
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" displayGenericVehicleImage />
<vehicleBanner class="mb-3" cmsWidgetName="VehicleBannerWidget" displayGenericVehicleImage />
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
:hasBackButton="true"
@ -13,13 +13,13 @@
<div class="fade-on-route-transition">
<modelQuestion v-model="selectedModel" ref="modelQuestion" cmsWidgetName="VehicleModelQuestion" />
</div>
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
@back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</template>
<script>
// Components
import modelQuestion from "@/layouts/vehicle-model/model-question/model-question";
@ -27,11 +27,11 @@
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";
export default {
name: "vehicle-model",
data() {
@ -45,7 +45,7 @@
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const modelQuestionInitialDataPromise =
modelQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
@ -57,9 +57,9 @@
promise: modelQuestionInitialDataPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
@ -68,7 +68,7 @@
);
});
},
methods: {
backButtonAction() {
// route to move backwards
@ -77,7 +77,7 @@
this.$route
);
},
arePagePrerequisitesValid()
arePagePrerequisitesValid()
{
if(this.mainStore.order.vehicle.make){
return true;
@ -109,4 +109,3 @@
},
};
</script>

View file

@ -3,6 +3,7 @@
<div class="page-container-grouped-styles vehicle-parts">
<siteHeader ref="siteHeader" cmsWidgetName="SiteHeaderWidget" />
<vehicleBanner
class="mb-3"
ref="vehicleBanner"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />

View file

@ -3,7 +3,7 @@
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" displayGenericVehicleImage />
<vehicleBanner cmsWidgetName="VehicleBannerWidget" class="mb-3" displayGenericVehicleImage />
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
:hasBackButton="true"
@ -15,7 +15,7 @@
ref="styleQuestion"
cmsWidgetName="VehicleStyleQuestion" />
</div>
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
@back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
@ -65,7 +65,7 @@ export default {
];
const resultMap = await settleAllPromises(promiseResultMap);
const visitedVehicleDamage = useMainStore().pageData(issPageValues.VEHICLE_DAMAGE) ? true : false;
// If we have exactly one style then navigate directly to vehicle-damage
@ -117,7 +117,7 @@ export default {
},
computed: {
backButtonAccessibleText()
backButtonAccessibleText()
{
return this.getCmsContent(this.cmsWidgetName, "BackButtonAccessibleText")
}

View file

@ -3,23 +3,23 @@
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="select-car">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true"/>
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mb-3" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<div class="fade-on-route-transition">
<yearQuestion
<yearQuestion
class="fade-on-route-transition"
v-model="selectedYear"
ref="yearQuestion"
cmsWidgetName="VehicleYearQuestion"
v-model="selectedYear"
ref="yearQuestion"
cmsWidgetName="VehicleYearQuestion"
/>
</div>
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
<siteFooter cmsWidgetName="SiteFooterWidget" ref="siteFooter"
@back-clicked="backButtonAction" :isForwardButtonHidden="shouldHideForwardButton" />
</div>
</div>
</div>
</template>
<script>
// Components
import yearQuestion from "@/layouts/vehicle-year/year-question/year-question";
@ -27,11 +27,11 @@
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";
export default {
name: "vehicle-year",
data() {
@ -41,12 +41,12 @@
};
},
computed: {},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const yearQuestionInitialDataPromise = yearQuestion.methods.loadInitialData();
// Settle promises and get results
const promiseResultMap = [
{
@ -58,9 +58,9 @@
promise: yearQuestionInitialDataPromise,
},
];
let resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
@ -73,8 +73,8 @@
watch: {
selectedYear(year) {
const parsedYear = parseInt(year);
this.mainStore.updateVehicleYear( parsedYear );
this.mainStore.updateVehicleYear( parsedYear );
this.$router.navigate(
this.navigationScenarios.SELECTED_YEAR,
this.$route
@ -89,7 +89,7 @@
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
},
components: {
yearQuestion,
siteHeader,
@ -99,4 +99,3 @@
},
};
</script>

View file

@ -9,6 +9,7 @@
cmsWidgetName="SiteHeaderWidget"
/>
<vehicleBanner
class="mb-3"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
@ -82,7 +83,7 @@ export default {
activeVehicleLookupAlertType: null,
needToLookupVehicle: true,
vehicleFromLookup: null,
vin: null,
vin: null,
};
},
provide() {
@ -130,7 +131,7 @@ export default {
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);
@ -146,29 +147,29 @@ export default {
}
// Add vin bcs the response from the service doesn't contain vin
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, { vin: this.vin });
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, { vin: this.vin });
}
if (this.needToLookupVehicle && this.isCarIdDifferentFromTheStore) {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NOT_MATCHED;
if (this.needToLookupVehicle && this.isCarIdDifferentFromTheStore) {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NOT_MATCHED;
const vehicleYearMakeModel = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model}`;
this.$refs.siteFooter.updateButtonText(`Continue with ${vehicleYearMakeModel}`);
this.$refs.siteFooter.removeLoader();
this.needToLookupVehicle = false;
return;
}
let isSelectedGlassAvailableForVehicle = true;
if (this.isCarIdDifferentFromTheStore) {
isSelectedGlassAvailableForVehicle =
await isGlassAvailableForCarId(this.vehicleFromLookup.carId);
}
let isSelectedGlassAvailableForVehicle = true;
if (this.isCarIdDifferentFromTheStore) {
isSelectedGlassAvailableForVehicle =
await isGlassAvailableForCarId(this.vehicleFromLookup.carId);
}
// navigate back to vehicle-damage
if (this.isCarIdDifferentFromTheStore && !isSelectedGlassAvailableForVehicle) {
if (this.isCarIdDifferentFromTheStore && !isSelectedGlassAvailableForVehicle) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
@ -179,8 +180,8 @@ export default {
// navigate() doesn't stop the processing flow
return;
}
}
this.mainStore.updateVehicle(this.vehicleFromLookup);
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
if (partsOrQuestionsResponse.error) {
@ -194,7 +195,7 @@ export default {
await this.navigateForward(partsOrQuestionsResponse.data.partsOrQuestions, this);
},
async getPartsOrQuestions() {
try {
try {
const response = await this.mainStore.getPartsOrQuestions();
return response;
@ -209,15 +210,15 @@ export default {
async lookupVehicleByVin(vin) {
try {
return await this.mainStore.lookupVehicleByVin(vin);
}
catch (responseError) {
}
catch (responseError) {
return {
error: {
status: responseError.status,
},
};
}
},
},
resetActiveAlert() {
this.activeVehicleLookupAlertType = null;
},

View file

@ -34,7 +34,7 @@
</div>
<div class="row">
<div class="col">
<textBlock cmsWidgetName="DamageDateEstimateWidget" typeStyle="caption" />
<textBlock cmsWidgetName="DamageDateEstimateWidget" typeStyle="caption" class="mt-2" />
</div>
</div>
<div class="row mt-4">

View file

@ -235,7 +235,7 @@ const routingTable = function(store) {
},
{
scenario: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS,
destinationIssPageValue: issPageValues.ESTIMATE,
destinationIssPageValue: issPageValues.VEHICLE_LOOKUP,
},
{
scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS,

View file

@ -701,6 +701,34 @@ export const useMainStore = defineStore({
//Save new values
this.updatePartQuestionAnswers(partQuestionAnswersArray);
},
saveMoldingQuestionAnswers(moldingQuestionAnswersArray) {
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
this.order.damage.moldingQuestionAnswers,
"result"
);
const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(
moldingQuestionAnswersArray,
"result"
);
const haveMoldingQuestionAnswersChanged =
sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length ||
!sortedPreviousResultsArray?.every(
(x, i) => x.result === sortedMoldingQuestionAnswersArray[i].result
);
if (haveMoldingQuestionAnswersChanged) {
this.updateGlassParts(null);
this.updateSupportingItems(null);
this.updateCapabilityQuestionAnswers(null);
this.updatePageData({
page: issPageValues.CAPABILITY_QUESTIONS,
data: null,
});
}
// Save new values
this.updateMoldingQuestionAnswers(moldingQuestionAnswersArray);
},
addEventToBus (event) {
this.applicationUser.eventBus.push(event);

View file

@ -25,7 +25,7 @@ h4,.h4 {
font-weight: 300;
}
h5,.h5 {
line-height: 1.325;
line-height: 1.6;
font-weight: 400;
}
h6,.h6 {
@ -64,4 +64,4 @@ caption,
font-size: 1rem !important;
line-height: 1.4;
font-weight: 500;
}
}