Merged from CSR-1012
This commit is contained in:
commit
6b24f56a2b
24 changed files with 290 additions and 150 deletions
|
|
@ -5,7 +5,10 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
|
||||||
:class="
|
:class="
|
||||||
isOverflowScrollable ? 'button-question button-question-overflow' : 'button-question'
|
isOverflowScrollable ? 'button-question button-question-overflow' : 'button-question'
|
||||||
">
|
">
|
||||||
<div v-if="questionText && answers && answers.length > 0" class="question-text d-flex">
|
<div
|
||||||
|
v-if="questionText && answers && answers.length > 0"
|
||||||
|
class="question-text d-flex"
|
||||||
|
:class="{ 'small-question-text': isSmallQuestionText }">
|
||||||
<span class="fw-bold w-100">{{ questionText }}</span>
|
<span class="fw-bold w-100">{{ questionText }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -124,6 +127,7 @@ export default {
|
||||||
useTextForValue: Boolean,
|
useTextForValue: Boolean,
|
||||||
valueToLogType: String,
|
valueToLogType: String,
|
||||||
additionalButtonStyling: String,
|
additionalButtonStyling: String,
|
||||||
|
isSmallQuestionText: Boolean,
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
if (this.buttonTypeObject) {
|
if (this.buttonTypeObject) {
|
||||||
|
|
@ -137,13 +141,15 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getFieldSetClasses() {
|
getFieldSetClasses() {
|
||||||
if (this.isOverflowScrollable) {
|
const baseClasses = this.isOverflowScrollable
|
||||||
return "container-fluid overflow-scroll position-absolute px-5 pt-1 py-0";
|
? "container-fluid overflow-scroll position-absolute px-5 pt-1 py-0"
|
||||||
} else if (this.buttonTypeString == "listCard") {
|
: this.buttonTypeString == "listCard"
|
||||||
return "w-100";
|
? "w-100"
|
||||||
} else {
|
: "";
|
||||||
return "";
|
const withSmallQuestionClass = this.isSmallQuestionText
|
||||||
}
|
? baseClasses + " small-question-text"
|
||||||
|
: baseClasses;
|
||||||
|
return withSmallQuestionClass;
|
||||||
},
|
},
|
||||||
getComponentLoopWrapperClasses() {
|
getComponentLoopWrapperClasses() {
|
||||||
let classes;
|
let classes;
|
||||||
|
|
@ -210,7 +216,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatString(str) {
|
formatString(str) {
|
||||||
return str?.replaceAll(" ", "-");
|
return String(str).replaceAll(" ", "-");
|
||||||
},
|
},
|
||||||
setLastValuePushedToGa(lastValuePushedToGa) {
|
setLastValuePushedToGa(lastValuePushedToGa) {
|
||||||
this.lastValuePushedToGa = lastValuePushedToGa;
|
this.lastValuePushedToGa = lastValuePushedToGa;
|
||||||
|
|
@ -260,19 +266,18 @@ export default {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.small-question-text {
|
||||||
.vehicle-parts {
|
&.question-text {
|
||||||
.question-text {
|
|
||||||
span {
|
span {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin: 0 0 0.5rem 0;
|
margin: 1rem 0 0.5rem 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.question-text {
|
&.question-text {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
fieldset {
|
& fieldset {
|
||||||
.ui-radio {
|
.ui-radio {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import Modal from "./modal";
|
import Modal from "./modal";
|
||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
const modalId = "modal-one";
|
const modalId = "modal-one";
|
||||||
const footerButtonText = "Sample footer text here.";
|
const footerButtonText = "Sample footer text here.";
|
||||||
const headerText = "Sample header text here.";
|
const headerText = "Sample header text here.";
|
||||||
|
|
||||||
|
global.crypto = crypto;
|
||||||
|
|
||||||
describe("modal.vue", () => {
|
describe("modal.vue", () => {
|
||||||
it("Should display footer button text when footerButtonText is defined", async () => {
|
it("Should display footer button text when footerButtonText is defined", async () => {
|
||||||
const wrapper = shallowMount(Modal, {
|
const wrapper = shallowMount(Modal, {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import { mount } from "@vue/test-utils";
|
import { mount } from "@vue/test-utils";
|
||||||
import contentGroupModal from "./content-group-modal";
|
import contentGroupModal from "./content-group-modal";
|
||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
|
global.crypto = crypto;
|
||||||
|
|
||||||
describe("content-group-modal.vue", () => {
|
describe("content-group-modal.vue", () => {
|
||||||
it("Should display header text when HeaderText is defined in the CMS", async () => {
|
it("Should display header text when HeaderText is defined in the CMS", async () => {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,11 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHerita
|
||||||
|
|
||||||
// If navigating to a specific page, and that page is not part of the vin pages.
|
// If navigating to a specific page, and that page is not part of the vin pages.
|
||||||
// Return that page, so that it can navigate like normal.
|
// Return that page, so that it can navigate like normal.
|
||||||
if (toRoute.query[queryStrings.FMG_PAGE] !== undefined && !isVinRelatedPage(toRoute)) {
|
if (
|
||||||
|
toRoute.query[queryStrings.FMG_PAGE] !== undefined &&
|
||||||
|
toRoute.query[queryStrings.FMG_PAGE] !== fmgPageValues.QUOTE &&
|
||||||
|
!isVinRelatedPage(toRoute)
|
||||||
|
) {
|
||||||
return overrideYmmsDirectionIfNeeded(toRoute);
|
return overrideYmmsDirectionIfNeeded(toRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,6 +111,7 @@ async function getLatestPageForRedirection() {
|
||||||
const capabilityQuestionsComponent = await getLazyLoadedComponent(
|
const capabilityQuestionsComponent = await getLazyLoadedComponent(
|
||||||
fmgPageValues.CAPABILITY_QUESTIONS
|
fmgPageValues.CAPABILITY_QUESTIONS
|
||||||
);
|
);
|
||||||
|
const quoteComponent = await getLazyLoadedComponent(fmgPageValues.QUOTE);
|
||||||
|
|
||||||
const skipVin = await skipVinLookup();
|
const skipVin = await skipVinLookup();
|
||||||
|
|
||||||
|
|
@ -121,7 +126,9 @@ async function getLatestPageForRedirection() {
|
||||||
} else if (!estimateComponent.methods.arePagePrerequisitesValid()) {
|
} else if (!estimateComponent.methods.arePagePrerequisitesValid()) {
|
||||||
return fmgPageValues.VEHICLE_DAMAGE;
|
return fmgPageValues.VEHICLE_DAMAGE;
|
||||||
} else {
|
} else {
|
||||||
if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) {
|
if (quoteComponent.methods.arePagePrerequisitesValid()) {
|
||||||
|
return fmgPageValues.QUOTE;
|
||||||
|
} else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) {
|
||||||
return fmgPageValues.CAPABILITY_QUESTIONS;
|
return fmgPageValues.CAPABILITY_QUESTIONS;
|
||||||
} else if (moldingQuestionsComponent.methods.arePagePrerequisitesValid()) {
|
} else if (moldingQuestionsComponent.methods.arePagePrerequisitesValid()) {
|
||||||
return fmgPageValues.MOLDING_QUESTIONS;
|
return fmgPageValues.MOLDING_QUESTIONS;
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ export async function loadSessionIfPresent(isConceptInsurance) {
|
||||||
funnelCookie.ReferralCorrelationId,
|
funnelCookie.ReferralCorrelationId,
|
||||||
isConceptInsurance
|
isConceptInsurance
|
||||||
)
|
)
|
||||||
).data;
|
)?.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
|
||||||
defineRule(
|
defineRule(
|
||||||
"email-address-format",
|
"email-address-format",
|
||||||
regex(
|
regex(
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
|
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
errorMessages.EMAIL_ADDRESS_FORMAT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
|
||||||
defineRule(
|
defineRule(
|
||||||
"email-address-format",
|
"email-address-format",
|
||||||
regex(
|
regex(
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
|
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
errorMessages.EMAIL_ADDRESS_FORMAT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -223,6 +223,25 @@ export default {
|
||||||
} else if (this.$store.getters.order.referralNumber?.length === 6) {
|
} else if (this.$store.getters.order.referralNumber?.length === 6) {
|
||||||
await this.navigateForwardWithSingleCarMatch();
|
await this.navigateForwardWithSingleCarMatch();
|
||||||
} else if (this.isRepair) {
|
} else if (this.isRepair) {
|
||||||
|
const supportingItemsPromise = await this.dispatchStoreAction(
|
||||||
|
storeActions.GET_SUPPORTING_ITEMS
|
||||||
|
);
|
||||||
|
|
||||||
|
const promiseResultMap = [
|
||||||
|
{
|
||||||
|
resultKey: "supportingItems",
|
||||||
|
promise: supportingItemsPromise,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
|
|
||||||
|
this.dispatchStoreAction(
|
||||||
|
this.storeActions.SAVE_SUPPORTING_ITEMS,
|
||||||
|
resultMap.supportingItems,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
// call saveSession here - navigateWithSaving saves too late in the flow
|
// call saveSession here - navigateWithSaving saves too late in the flow
|
||||||
await saveSession({});
|
await saveSession({});
|
||||||
return this.$router.navigateWithoutSaving(
|
return this.$router.navigateWithoutSaving(
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
|
||||||
defineRule(
|
defineRule(
|
||||||
"email-address-format",
|
"email-address-format",
|
||||||
regex(
|
regex(
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
|
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
errorMessages.EMAIL_ADDRESS_FORMAT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
128
src/layouts/quote/quote.spec.js
Normal file
128
src/layouts/quote/quote.spec.js
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
import { shallowMount, flushPromises } from "@vue/test-utils";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { applicationConfig } from "@/constants/application-config";
|
||||||
|
import quote from "@/layouts/quote/quote.vue";
|
||||||
|
import store from "@/store";
|
||||||
|
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
||||||
|
jest.mock("@/store", () => ({
|
||||||
|
commit: jest.fn(),
|
||||||
|
dispatch: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 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(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||||
|
navigateToHeritageFunnel: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock(
|
||||||
|
"@/store",
|
||||||
|
() => {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
{ virtual: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
store.getters = {
|
||||||
|
order: {
|
||||||
|
accountNumber: applicationConfig.CASH_ACCOUNT_NUMBER,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
insuranceCoverage: {},
|
||||||
|
isInsurance: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
// reset store after each test
|
||||||
|
store.getters = {
|
||||||
|
order: {
|
||||||
|
accountNumber: applicationConfig.CASH_ACCOUNT_NUMBER,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
insuranceCoverage: {},
|
||||||
|
isInsurance: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("quote.vue", () => {
|
||||||
|
test("IsInsurance false should navigateWithSaving", async () => {
|
||||||
|
//Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
router: {
|
||||||
|
navigateWithSaving: jest.fn(),
|
||||||
|
},
|
||||||
|
route: { quote },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
store.getters.payment = {
|
||||||
|
insuranceCoverage: {},
|
||||||
|
isInsurance: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
//Act
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("IsInsurance true should navigateToHeritageFunnel", async () => {
|
||||||
|
//Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
customMountOptions: {
|
||||||
|
router: {
|
||||||
|
navigateWithSaving: jest.fn(),
|
||||||
|
},
|
||||||
|
route: { quote },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
store.getters.payment = {
|
||||||
|
insuranceCoverage: {},
|
||||||
|
isInsurance: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapper.vm.dispatchStoreAction = jest.fn(() => {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
//Act
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
expect(navigateToHeritage.navigateToHeritageFunnel).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupMocks({ customMountOptions }) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
...customMountOptions,
|
||||||
|
});
|
||||||
|
|
||||||
|
mountOptions.global.mocks["$store"] = store;
|
||||||
|
mountOptions["attachTo"] = document.body;
|
||||||
|
|
||||||
|
const wrapper = shallowMount(quote, mountOptions);
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
@ -183,6 +183,7 @@ export default {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.getters.order.accountNumber != applicationConfig.CASH_ACCOUNT_NUMBER) {
|
if (this.$store.getters.order.accountNumber != applicationConfig.CASH_ACCOUNT_NUMBER) {
|
||||||
this.supportingItems = this.filterOutFees(this.supportingItems);
|
this.supportingItems = this.filterOutFees(this.supportingItems);
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +194,15 @@ export default {
|
||||||
);
|
);
|
||||||
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false);
|
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false);
|
||||||
|
|
||||||
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
|
const payment = this.$store.getters.payment;
|
||||||
|
if (payment.isInsurance) {
|
||||||
|
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
|
||||||
|
} else {
|
||||||
|
this.$router.navigateWithSaving(
|
||||||
|
this.navigationScenarios.CLICKED_FORWARD_WITH_CASH,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ export default {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
availableLineItems() {
|
availableLineItems() {
|
||||||
if (this.$store.getters.lineItems.supportingItems) {
|
if (this.$store.getters.lineItems.vaps) {
|
||||||
this.selectDefaultPackage();
|
this.selectDefaultPackage();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -213,18 +213,20 @@ export default {
|
||||||
selectDefaultPackage() {
|
selectDefaultPackage() {
|
||||||
const vapsFromStore = this.$store.getters.lineItems.vaps;
|
const vapsFromStore = this.$store.getters.lineItems.vaps;
|
||||||
let lowestTierForPackage = packageNames.TIER_ONE;
|
let lowestTierForPackage = packageNames.TIER_ONE;
|
||||||
vapsFromStore.every((vapsItem) => {
|
if (vapsFromStore.length > 0) {
|
||||||
let lowestTierForThisItem = this.getLowestTierForThisItem(vapsItem);
|
vapsFromStore.every((vapsItem) => {
|
||||||
if (lowestTierForThisItem === packageNames.TIER_THREE) {
|
let lowestTierForThisItem = this.getLowestTierForThisItem(vapsItem);
|
||||||
lowestTierForPackage = packageNames.TIER_THREE;
|
if (lowestTierForThisItem === packageNames.TIER_THREE) {
|
||||||
return false;
|
lowestTierForPackage = packageNames.TIER_THREE;
|
||||||
} else if (lowestTierForThisItem === packageNames.TIER_TWO) {
|
return false;
|
||||||
lowestTierForPackage = packageNames.TIER_TWO;
|
} else if (lowestTierForThisItem === packageNames.TIER_TWO) {
|
||||||
return true;
|
lowestTierForPackage = packageNames.TIER_TWO;
|
||||||
} else {
|
return true;
|
||||||
return true;
|
} else {
|
||||||
}
|
return true;
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
this.selectedPackageName = lowestTierForPackage;
|
this.selectedPackageName = lowestTierForPackage;
|
||||||
},
|
},
|
||||||
getLowestTierForThisItem(vapsItem) {
|
getLowestTierForThisItem(vapsItem) {
|
||||||
|
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="container-fluid shadow rounded-3 p-2 position-relative make-tall">
|
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
|
||||||
<h1>Reveal Confetti Page Placeholder</h1>
|
|
||||||
<funnelFooter
|
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
|
||||||
ref="funnelFooter"
|
|
||||||
@back-clicked="backButtonAction" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Components
|
|
||||||
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
|
||||||
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer";
|
|
||||||
|
|
||||||
// Supporting Files
|
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
|
||||||
import { storeActions } from "@/constants/store-actions";
|
|
||||||
import store from "@/store";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "quote",
|
|
||||||
async beforeRouteEnter(to, from, next) {
|
|
||||||
// Call APIs
|
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
|
||||||
|
|
||||||
// Settle promises and get results
|
|
||||||
const promiseResultMap = [
|
|
||||||
{
|
|
||||||
resultKey: "cmsContent",
|
|
||||||
promise: cmsContentPromise,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
|
||||||
|
|
||||||
// Call the "next" function to complete the transition to this page.
|
|
||||||
next((vm) => {
|
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
backButtonAction() {
|
|
||||||
// route to move backwards
|
|
||||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
|
||||||
},
|
|
||||||
arePagePrerequisitesValid() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
resetDependentState() {
|
|
||||||
// Set
|
|
||||||
store.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
|
||||||
// Invokes
|
|
||||||
store.dispatch(storeActions.RESET_PARTS_AND_DEPS);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {},
|
|
||||||
components: {
|
|
||||||
funnelHeader,
|
|
||||||
funnelFooter,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||||
<div class="page-container-grouped-styles">
|
<div class="page-container-grouped-styles">
|
||||||
|
<loadingModal ref="loadingModal" />
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
||||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
<serviceZipModalQuestion
|
<serviceZipModalQuestion
|
||||||
|
|
@ -17,6 +18,7 @@
|
||||||
workspaceRequirementsWidgetName="WorkspaceRequirementsWidget" />
|
workspaceRequirementsWidgetName="WorkspaceRequirementsWidget" />
|
||||||
<funnel-footer
|
<funnel-footer
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
ref="funnelFooter"
|
||||||
:isForwardActionDisabled="!meta.valid"
|
:isForwardActionDisabled="!meta.valid"
|
||||||
@back-clicked="backButtonAction"
|
@back-clicked="backButtonAction"
|
||||||
@ForwardClicked="forwardButtonAction" />
|
@ForwardClicked="forwardButtonAction" />
|
||||||
|
|
@ -31,11 +33,11 @@ import mobileLocationModalQuestions from "@/layouts/service-location/mobile-loca
|
||||||
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
||||||
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer";
|
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer";
|
||||||
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
||||||
|
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||||
//Supporting Files
|
|
||||||
import { Form } from "vee-validate";
|
import { Form } from "vee-validate";
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "service-location",
|
name: "service-location",
|
||||||
|
|
@ -119,8 +121,13 @@ export default {
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
backButtonAction() {},
|
|
||||||
forwardButtonAction() {},
|
backButtonAction() {
|
||||||
|
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||||
|
},
|
||||||
|
forwardButtonAction() {
|
||||||
|
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
serviceZipModalQuestion,
|
serviceZipModalQuestion,
|
||||||
|
|
@ -129,6 +136,7 @@ export default {
|
||||||
funnelFooter,
|
funnelFooter,
|
||||||
funnelSubHeader,
|
funnelSubHeader,
|
||||||
Form,
|
Form,
|
||||||
|
loadingModal,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
onModalOpened() {
|
onModalOpened() {
|
||||||
|
this.serviceZipCodeInput = this.serviceZipModel.zipCode;
|
||||||
this.focusOnZipInput();
|
this.focusOnZipInput();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
textPosition="text-start"
|
textPosition="text-start"
|
||||||
:loaderEnabled="false"
|
:loaderEnabled="false"
|
||||||
isRequired
|
isRequired
|
||||||
|
isSmallQuestionText
|
||||||
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
|
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
|
||||||
:validationRules="partValidationRules" />
|
:validationRules="partValidationRules" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
||||||
<div class="page-container-grouped-styles vehicle-parts">
|
<div class="page-container-grouped-styles vehicle-parts small-question-text">
|
||||||
<loadingModal ref="loadingModal" />
|
<loadingModal ref="loadingModal" />
|
||||||
<funnelHeader ref="funnelHeader" cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader ref="funnelHeader" cmsWidgetName="FunnelHeaderWidget" />
|
||||||
<vehicleBanner
|
<vehicleBanner
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
fmg
|
|
||||||
<template>
|
<template>
|
||||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||||
<div class="page-container-grouped-styles">
|
<div class="page-container-grouped-styles">
|
||||||
|
|
@ -145,7 +144,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
|
||||||
defineRule(
|
defineRule(
|
||||||
"email-address-format",
|
"email-address-format",
|
||||||
regex(
|
regex(
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
|
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
errorMessages.EMAIL_ADDRESS_FORMAT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -64,17 +64,14 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getTierOnePackagePrice(lineItems) {
|
getTierOnePackagePrice(lineItems) {
|
||||||
let totalPrice = 0;
|
let lineItemsToPrice = lineItems.filter((lineItem) => {
|
||||||
lineItems.forEach((lineItem) => {
|
return (
|
||||||
const partType = lineItem.partType.toUpperCase();
|
lineItem.partType != partTypeStrings.FRONT_WIPER &&
|
||||||
if (
|
lineItem.partType != partTypeStrings.REAR_WIPER &&
|
||||||
partType != partTypeStrings.FRONT_WIPER &&
|
lineItem.partType != partTypeStrings.RAIN_DEFENSE
|
||||||
partType != partTypeStrings.REAR_WIPER &&
|
);
|
||||||
partType != partTypeStrings.RAIN_DEFENSE
|
|
||||||
) {
|
|
||||||
totalPrice += this.getTotalLineItemPrice(lineItem);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
let totalPrice = this.getTotalPriceOfAllLineItemsAndChildParts(lineItemsToPrice);
|
||||||
return totalPrice;
|
return totalPrice;
|
||||||
},
|
},
|
||||||
filterOutFees(lineItems) {
|
filterOutFees(lineItems) {
|
||||||
|
|
@ -86,6 +83,18 @@ export default {
|
||||||
});
|
});
|
||||||
return filteredLineItems;
|
return filteredLineItems;
|
||||||
},
|
},
|
||||||
|
getTotalPriceOfAllLineItemsAndChildParts(lineItems) {
|
||||||
|
let totalPrice = 0;
|
||||||
|
lineItems.forEach((lineItem) => {
|
||||||
|
totalPrice += this.getTotalLineItemPrice(lineItem);
|
||||||
|
if (lineItem.childParts) {
|
||||||
|
totalPrice += this.getTotalPriceOfAllLineItemsAndChildParts(
|
||||||
|
lineItem.childParts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return totalPrice;
|
||||||
|
},
|
||||||
getTotalLineItemPrice(lineItem) {
|
getTotalLineItemPrice(lineItem) {
|
||||||
return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice;
|
return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -485,11 +485,10 @@ export default {
|
||||||
this.hasGlassLocationWithMultipleParts(allPartsOrQuestions);
|
this.hasGlassLocationWithMultipleParts(allPartsOrQuestions);
|
||||||
const hasChildPartQuestions = this.hasChildPartQuestions(allPartsOrQuestions);
|
const hasChildPartQuestions = this.hasChildPartQuestions(allPartsOrQuestions);
|
||||||
const hasCapabilityQuestions = this.hasCapabilityQuestions(allPartsOrQuestions);
|
const hasCapabilityQuestions = this.hasCapabilityQuestions(allPartsOrQuestions);
|
||||||
const skipVinLookup = await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE);
|
|
||||||
|
|
||||||
const vin = self.$store.getters.vehicle.vin;
|
const vin = self.$store.getters.vehicle.vin;
|
||||||
let backNavigationScenario =
|
let backNavigationScenario =
|
||||||
!vin || vin === "" || skipVinLookup
|
!vin || vin === ""
|
||||||
? navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS
|
? navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS
|
||||||
: navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS;
|
: navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ const fmgPageValues = {
|
||||||
MOLDING_QUESTIONS: "molding-questions",
|
MOLDING_QUESTIONS: "molding-questions",
|
||||||
CAPABILITY_QUESTIONS: "capability-questions",
|
CAPABILITY_QUESTIONS: "capability-questions",
|
||||||
LICENSE_PLATE_LOOKUP: "license-plate-lookup",
|
LICENSE_PLATE_LOOKUP: "license-plate-lookup",
|
||||||
REVEAL: "reveal",
|
|
||||||
ESTIMATE: "estimate",
|
ESTIMATE: "estimate",
|
||||||
ADDRESS_VEHICLES: "address-vehicles",
|
ADDRESS_VEHICLES: "address-vehicles",
|
||||||
QUOTE: "quote",
|
QUOTE: "quote",
|
||||||
|
SERVICE_LOCATION: "service-location",
|
||||||
HERITAGE: "heritage",
|
HERITAGE: "heritage",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ const navigationScenarios = {
|
||||||
// General
|
// General
|
||||||
CLICKED_BACK: "CLICKED_BACK",
|
CLICKED_BACK: "CLICKED_BACK",
|
||||||
CLICKED_FORWARD: "CLICKED_FORWARD",
|
CLICKED_FORWARD: "CLICKED_FORWARD",
|
||||||
|
CLICKED_FORWARD_WITH_CASH: "CLICKED_FORWARD_WITH_CASH",
|
||||||
|
|
||||||
// YMMS
|
// YMMS
|
||||||
SELECTED_YEAR: "SELECTED_YEAR",
|
SELECTED_YEAR: "SELECTED_YEAR",
|
||||||
|
|
|
||||||
|
|
@ -79,15 +79,6 @@ const routingTable = function (store) {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
fmgPageValue: fmgPageValues.REVEAL,
|
|
||||||
maps: [
|
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_BACK,
|
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
fmgPageValue: fmgPageValues.VIN_LOOKUP,
|
fmgPageValue: fmgPageValues.VIN_LOOKUP,
|
||||||
maps: [
|
maps: [
|
||||||
|
|
@ -305,10 +296,6 @@ const routingTable = function (store) {
|
||||||
{
|
{
|
||||||
fmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
fmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
||||||
maps: [
|
maps: [
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
|
||||||
destinationFmgPageValue: fmgPageValues.REVEAL,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS,
|
scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
|
||||||
|
|
@ -420,6 +407,19 @@ const routingTable = function (store) {
|
||||||
scenario: navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS,
|
scenario: navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CASH,
|
||||||
|
destinationFmgPageValue: fmgPageValues.SERVICE_LOCATION,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fmgPageValue: fmgPageValues.SERVICE_LOCATION,
|
||||||
|
maps: [
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK,
|
||||||
|
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { experimentTriggers } from "@/constants/experiments";
|
||||||
import { damageLocationsSelected } from "@/constants/damage-locations-selected";
|
import { damageLocationsSelected } from "@/constants/damage-locations-selected";
|
||||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
|
import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js";
|
||||||
|
|
||||||
// Export State
|
// Export State
|
||||||
const getDefaultState = () => {
|
const getDefaultState = () => {
|
||||||
|
|
@ -1059,23 +1060,32 @@ export const actions = {
|
||||||
referralCorrelationId: referralCorrelationId,
|
referralCorrelationId: referralCorrelationId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then(
|
||||||
// Flatten location and name properties
|
(response) => {
|
||||||
response.data.order.damage?.glassToReplace?.map((glass) => {
|
// Flatten location and name properties
|
||||||
glass.glassLocation = glass.location;
|
response.data.order.damage?.glassToReplace?.map((glass) => {
|
||||||
glass.glassName = glass.name;
|
glass.glassLocation = glass.location;
|
||||||
delete glass.location;
|
glass.glassName = glass.name;
|
||||||
delete glass.name;
|
delete glass.location;
|
||||||
return glass;
|
delete glass.name;
|
||||||
});
|
return glass;
|
||||||
|
});
|
||||||
|
|
||||||
// clear the state if the existing EON does not equal what is returned from loadSession
|
// clear the state if the existing EON does not equal what is returned from loadSession
|
||||||
if (context.state.order.eon && context.state.order.eon != response.data.eon) {
|
if (context.state.order.eon && context.state.order.eon != response.data.eon) {
|
||||||
|
context.commit(storeMutations.RESET_STATE);
|
||||||
|
}
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION,
|
||||||
|
response.data
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
deleteFunnelCookie();
|
||||||
context.commit(storeMutations.RESET_STATE);
|
context.commit(storeMutations.RESET_STATE);
|
||||||
}
|
}
|
||||||
context.commit(storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION, response.data);
|
);
|
||||||
return response;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Business domain actions
|
// Business domain actions
|
||||||
|
|
@ -1422,7 +1432,7 @@ export const actions = {
|
||||||
`${availableLineItemsFormattedForRequest}`;
|
`${availableLineItemsFormattedForRequest}`;
|
||||||
const lineItemServerData = context.getters.order.lineItems.serverData;
|
const lineItemServerData = context.getters.order.lineItems.serverData;
|
||||||
if (lineItemServerData) {
|
if (lineItemServerData) {
|
||||||
queryString += `&ServerData=${lineItemServerData}`;
|
queryString += `&ServerData=${encodeURIComponent(lineItemServerData)}`;
|
||||||
}
|
}
|
||||||
const response = await globalMethods.callHttpClient({
|
const response = await globalMethods.callHttpClient({
|
||||||
method: endpoints.PriceOrderItems.method,
|
method: endpoints.PriceOrderItems.method,
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,9 @@ html {
|
||||||
.form-test-error {
|
.form-test-error {
|
||||||
color: $red;
|
color: $red;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 500;
|
.small {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-test-invalid {
|
.form-test-invalid {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue