merging from develop, fixed conflicts with refactoring vehicle question page navigations
This commit is contained in:
commit
04ff118b55
24 changed files with 1557 additions and 1297 deletions
|
|
@ -7,8 +7,9 @@
|
||||||
:class="(q.questionSequence === currentQuestionNum) && 'current-question'"
|
:class="(q.questionSequence === currentQuestionNum) && 'current-question'"
|
||||||
:questionText="q.questionText"
|
:questionText="q.questionText"
|
||||||
:answers="q.answers"
|
:answers="q.answers"
|
||||||
:groupName="`${questionData.glassName}-${questionData.glassLocation}-${i}`"
|
:groupName="`${keyString}-${q.questionSequence}`"
|
||||||
v-model="selectedValue"
|
v-model="q.answerSelected"
|
||||||
|
@isCheckedChanged="handleChainCompleted"
|
||||||
isRequired
|
isRequired
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
/>
|
/>
|
||||||
|
|
@ -24,8 +25,8 @@ export default {
|
||||||
name: "questionChain",
|
name: "questionChain",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentQuestionNum: 1,
|
currentQuestionNum: 0,
|
||||||
questions: [{ "BlankObject": "NOT USED... placeholder for question #0 to simplify indexing"}],
|
questions: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -33,13 +34,13 @@ export default {
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
modelValue: Array,
|
modelValue: Array,
|
||||||
partIndex: Number,
|
partIndex: Number,
|
||||||
key: String,
|
keyString: String,
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
// validate form upon create to prevent out of sync / persistent valid states
|
// validate form upon create to prevent out of sync / persistent valid states
|
||||||
await useValidateForm(); // do a test validation check, without triggering full validation
|
await useValidateForm(); // do a test validation check, without triggering full validation
|
||||||
|
|
||||||
this.questionData.partQuestions.map((q, i) => {
|
this.questionData.map((q, i) => {
|
||||||
let answerPair = [];
|
let answerPair = [];
|
||||||
const question = {
|
const question = {
|
||||||
questionText: q.questionText,
|
questionText: q.questionText,
|
||||||
|
|
@ -47,7 +48,7 @@ export default {
|
||||||
answers: q.answers.map((a) => {
|
answers: q.answers.map((a) => {
|
||||||
answerPair.push(a.nextQuestionSequence ? a.nextQuestionSequence : a.answerResult);
|
answerPair.push(a.nextQuestionSequence ? a.nextQuestionSequence : a.answerResult);
|
||||||
return {
|
return {
|
||||||
Text: a.answerText + " (" + a.answerResult + a.nextQuestionSequence + ")",
|
Text: a.answerText,
|
||||||
// Name will either be nextQuestionSequence or answerResult
|
// Name will either be nextQuestionSequence or answerResult
|
||||||
// Name will be used by list-button as the input value.
|
// Name will be used by list-button as the input value.
|
||||||
// It must be a single string or number, so concatenating together a string with
|
// It must be a single string or number, so concatenating together a string with
|
||||||
|
|
@ -59,34 +60,32 @@ export default {
|
||||||
nextQuestionSequence: a.nextQuestionSequence,
|
nextQuestionSequence: a.nextQuestionSequence,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
answerSelected: "",
|
answerSelected: q.answerSelected || "",
|
||||||
};
|
};
|
||||||
question.answerPair = answerPair;
|
question.answerPair = answerPair;
|
||||||
if (!q.suppressQuestion) {
|
if (!q.isDuplicateQuestion) {
|
||||||
this.questions.push(question);
|
this.questions.push(question);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// set this.currentQuestionNum to first valid question
|
|
||||||
this.currentQuestionNum = this.questions[1].questionSequence;
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
selectedValue: {
|
|
||||||
get: function() {
|
|
||||||
return this.modelValue[0];
|
|
||||||
},
|
|
||||||
set: function(returnedAnswer) {
|
|
||||||
const isQuestionChainComplete = this.handleReturnedAnswer(returnedAnswer);
|
|
||||||
|
|
||||||
if (isQuestionChainComplete) {
|
if (!this.modelValue?.length > 0) {
|
||||||
this.$emit("update:modelValue", isQuestionChainComplete);
|
// set this.currentQuestionNum to first valid question
|
||||||
}
|
this.currentQuestionNum = this.questions[0].questionSequence;
|
||||||
}
|
// scroll the next question into view
|
||||||
},
|
this.$nextTick(() => {
|
||||||
currentQuestion() {
|
document.querySelector('.current-question').scrollIntoView({behavior: "smooth"});
|
||||||
return this.questions[this.currentQuestionNum];
|
})
|
||||||
},
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleChainCompleted(returnedAnswer) {
|
||||||
|
const isQuestionChainComplete = this.handleReturnedAnswer(returnedAnswer.value);
|
||||||
|
|
||||||
|
if (isQuestionChainComplete) {
|
||||||
|
this.$emit("update:modelValue", isQuestionChainComplete);
|
||||||
|
}
|
||||||
|
},
|
||||||
handleReturnedAnswer(returnedAnswer) { // this method will return either a final answer or Boolean false
|
handleReturnedAnswer(returnedAnswer) { // this method will return either a final answer or Boolean false
|
||||||
if (!returnedAnswer) { return false }
|
if (!returnedAnswer) { return false }
|
||||||
|
|
||||||
|
|
@ -103,7 +102,7 @@ export default {
|
||||||
this.questions.forEach((q) => {
|
this.questions.forEach((q) => {
|
||||||
// mark this question as "answered"
|
// mark this question as "answered"
|
||||||
if (q.questionSequence === questionNum) {
|
if (q.questionSequence === questionNum) {
|
||||||
q.answerSelected = questionAnswerText;
|
q.answerSelected = returnedAnswer;
|
||||||
q.answerNumber = questionNum;
|
q.answerNumber = questionNum;
|
||||||
}
|
}
|
||||||
// remove all previous answers after the index of this one in questions
|
// remove all previous answers after the index of this one in questions
|
||||||
|
|
@ -112,11 +111,14 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// update to next question index
|
|
||||||
this.currentQuestionNum = questionType === "nextQuestion" ? parseInt(questionAnswer) : questionNum; // update count to display next question
|
|
||||||
|
|
||||||
// return false if there's a nextQuestion... or return an object with "final" answers
|
// return false if there's a nextQuestion... or return an object with "final" answers
|
||||||
if (questionType === "nextQuestion") {
|
if (questionType === "nextQuestion") {
|
||||||
|
// update to next question index
|
||||||
|
this.currentQuestionNum = parseInt(questionAnswer); // update count to display next question
|
||||||
|
// scroll the next question into view
|
||||||
|
this.$nextTick(() => {
|
||||||
|
document.querySelector('.current-question').scrollIntoView({behavior: "smooth"});
|
||||||
|
})
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
const answeredQuestions = [];
|
const answeredQuestions = [];
|
||||||
|
|
@ -124,30 +126,23 @@ export default {
|
||||||
if (q.answerSelected) {
|
if (q.answerSelected) {
|
||||||
answeredQuestions.push({
|
answeredQuestions.push({
|
||||||
questionText: q.questionText,
|
questionText: q.questionText,
|
||||||
selectedAnswerText: q.answerSelected,
|
selectedAnswerText: q.answerSelected.split("|")[3],
|
||||||
questionNum: q.answerNumber,
|
questionNum: q.questionSequence,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// reset current question index
|
||||||
|
this.currentQuestionNum = 0; // reset count
|
||||||
|
|
||||||
return {
|
return {
|
||||||
answerResult: questionAnswer,
|
answerResult: questionAnswer,
|
||||||
answeredQuestions: answeredQuestions,
|
answeredQuestions: answeredQuestions,
|
||||||
partIndex: this.partIndex,
|
partIndex: this.partIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
currentQuestion: {
|
|
||||||
handler() {
|
|
||||||
// scrolls page to next active question
|
|
||||||
this.$nextTick(() => {
|
|
||||||
document.querySelector('.current-question').scrollIntoView({behavior: "smooth"});
|
|
||||||
})
|
|
||||||
},
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,14 @@ const endpoints = {
|
||||||
url: "/parts/api/v1/parts/parts",
|
url: "/parts/api/v1/parts/parts",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
|
GetCapabilityQuestions: {
|
||||||
|
url: "/parts/api/v1/parts/capability-questions",
|
||||||
|
method: "GET"
|
||||||
|
},
|
||||||
|
ApplyCapabilityAnswerToPart: {
|
||||||
|
url: "/parts/api/v1/parts/apply-capability-answer-to-part",
|
||||||
|
method: "POST"
|
||||||
|
},
|
||||||
SaveOrder: {
|
SaveOrder: {
|
||||||
url: "/order/api/v1/order/save",
|
url: "/order/api/v1/order/save",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ const storeActions = {
|
||||||
|
|
||||||
GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions",
|
GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions",
|
||||||
GET_PARTS: "getParts",
|
GET_PARTS: "getParts",
|
||||||
|
GET_CAPABILITY_QUESTIONS: "getCapabilityQuestions",
|
||||||
|
GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: "getPartFromCapabilityQuestionAnswer",
|
||||||
SAVE_ORDER: "saveOrder",
|
SAVE_ORDER: "saveOrder",
|
||||||
LOAD_ORDER: "loadOrder",
|
LOAD_ORDER: "loadOrder",
|
||||||
UPDATE_STORE_WITH_SAVE_ORDER_RESPONSE: "updateStoreWithSaveOrderResponse",
|
UPDATE_STORE_WITH_SAVE_ORDER_RESPONSE: "updateStoreWithSaveOrderResponse",
|
||||||
|
|
@ -55,6 +57,7 @@ const storeActions = {
|
||||||
SAVE_REGISTRATION_ADDRESS_LOOKUP: "saveRegistrationAddressLookup",
|
SAVE_REGISTRATION_ADDRESS_LOOKUP: "saveRegistrationAddressLookup",
|
||||||
SAVE_GLASS_PARTS: "saveGlassParts",
|
SAVE_GLASS_PARTS: "saveGlassParts",
|
||||||
SAVE_PART_QUESTION_ANSWERS: "savePartQuestionAnswers",
|
SAVE_PART_QUESTION_ANSWERS: "savePartQuestionAnswers",
|
||||||
|
SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers"
|
||||||
};
|
};
|
||||||
|
|
||||||
export { storeActions };
|
export { storeActions };
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ const storeMutations = {
|
||||||
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
|
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
|
||||||
UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace",
|
UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace",
|
||||||
UPDATE_PART_QUESTION_ANSWERS: "updatePartQuestionAnswers",
|
UPDATE_PART_QUESTION_ANSWERS: "updatePartQuestionAnswers",
|
||||||
|
UPDATE_CAPABILITY_QUESTION_ANSWERS: "updateCapabilityQuestionAnswers",
|
||||||
UPDATE_GLASS_PARTS: "updateGlassParts",
|
UPDATE_GLASS_PARTS: "updateGlassParts",
|
||||||
UPDATE_OTHER_PARTS: "updateOtherParts",
|
UPDATE_OTHER_PARTS: "updateOtherParts",
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,6 @@ export function updateOrCreateFunnelCookie() {
|
||||||
const wasClaimRegistrationDelayed = getFunnelCookie()?.HasDelayedClaimRegistration;
|
const wasClaimRegistrationDelayed = getFunnelCookie()?.HasDelayedClaimRegistration;
|
||||||
const shouldSuppressConceptFunnel = getFunnelCookie()?.SuppressConceptFunnel;
|
const shouldSuppressConceptFunnel = getFunnelCookie()?.SuppressConceptFunnel;
|
||||||
|
|
||||||
// Create the cookie
|
|
||||||
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}={}; path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()};`;
|
|
||||||
|
|
||||||
// Set up cookie with all the props.
|
// Set up cookie with all the props.
|
||||||
setFunnelCookieProperties({
|
setFunnelCookieProperties({
|
||||||
LastTouched: new Date().toUTCString(),
|
LastTouched: new Date().toUTCString(),
|
||||||
|
|
@ -48,14 +45,14 @@ export function getFunnelCookie() {
|
||||||
Removes cookie from browser.
|
Removes cookie from browser.
|
||||||
*/
|
*/
|
||||||
export function deleteFunnelCookie() {
|
export function deleteFunnelCookie() {
|
||||||
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}=; Max-Age=0; path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()}`;
|
createOrUpdateCookie(cookieNames.FUNNEL_SESSION_INFO, undefined, { maxAge: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Gets cookie domain value. Localhost will be empty "".
|
Gets cookie domain value. Localhost will be empty "".
|
||||||
*/
|
*/
|
||||||
export function getCookieDomainValue() {
|
export function getCookieDomainValue() {
|
||||||
return location.hostname.includes("localhost") ? "" : `domain=${getDomainWithoutSubdomain()};`;
|
return isLocalhost() ? "" : `domain=${getDomainWithoutSubdomain()};`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -106,10 +103,17 @@ export function getSessionIdValue(){
|
||||||
return '00000000-0000-0000-0000-000000000000';
|
return '00000000-0000-0000-0000-000000000000';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setCookieProperties(properties) {
|
/*
|
||||||
|
Updates session ID cookie with new expiration date
|
||||||
|
*/
|
||||||
|
export function updateSessionIdCookie() {
|
||||||
|
createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCookieProperties(properties, { useDefaultFunnelCookieAttributes = true, maxAge, isSecure }) {
|
||||||
if (typeof properties == "object") {
|
if (typeof properties == "object") {
|
||||||
Object.keys(properties).forEach(key => {
|
Object.keys(properties).forEach(key => {
|
||||||
document.cookie = `${key}=${properties[key]}`;
|
createOrUpdateCookie(key, properties[key], { useDefaultFunnelCookieAttributes, maxAge, isSecure });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -133,20 +137,39 @@ function setFunnelCookieProperties(properties) {
|
||||||
Object.keys(properties).forEach(key => {
|
Object.keys(properties).forEach(key => {
|
||||||
cookie[key] = properties[key];
|
cookie[key] = properties[key];
|
||||||
});
|
});
|
||||||
|
|
||||||
const cookieValueJson = JSON.stringify(cookie);
|
|
||||||
|
|
||||||
document.cookie = `${cookieNames.FUNNEL_SESSION_INFO}=${cookieValueJson}; path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cookieValueJson = JSON.stringify(cookie ?? {});
|
||||||
|
createOrUpdateCookie(cookieNames.FUNNEL_SESSION_INFO, cookieValueJson, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Used to create a cookie.
|
||||||
|
`useDefaultFunnelCookieAttributes` will set the path and domain to our defaults
|
||||||
|
*/
|
||||||
|
function createOrUpdateCookie(key, value = "", { useDefaultFunnelCookieAttributes = true, maxAge, isSecure = true }) {
|
||||||
|
let cookieToAdd = `${key}=${value}; `;
|
||||||
|
|
||||||
|
if (useDefaultFunnelCookieAttributes) {
|
||||||
|
cookieToAdd += `path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()} `;
|
||||||
|
}
|
||||||
|
if (isSecure && !isLocalhost()) {
|
||||||
|
cookieToAdd += `secure; `;
|
||||||
|
}
|
||||||
|
if (!isNaN(maxAge)) {
|
||||||
|
cookieToAdd += `max-age=${maxAge};`;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.cookie = cookieToAdd;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Gets current domain without the subdomain for cookie.
|
Gets current domain without the subdomain for cookie.
|
||||||
*/
|
*/
|
||||||
function getDomainWithoutSubdomain() {
|
function getDomainWithoutSubdomain() {
|
||||||
let url = location.hostname;
|
let url = location.hostname;
|
||||||
if (url.includes("localhost")) {
|
if (isLocalhost()) {
|
||||||
return "localhost";
|
return "localhost";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,3 +193,7 @@ function getCookieValueByName(name) {
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isLocalhost() {
|
||||||
|
return location.hostname.includes("localhost");
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
import { cookieNames } from "@/constants/cookie-names";
|
import { cookieNames } from "@/constants/cookie-names";
|
||||||
import { Form } from "vee-validate";
|
import { Form } from "vee-validate";
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
import { getCookieDomainValue } from "@/helpers/heritage-integration/cookie-helper";
|
import { getCookieDomainValue, setCookieProperties } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents, ValueToLogTypes } from "@/constants/analytics";
|
import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents, ValueToLogTypes } from "@/constants/analytics";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { routerParams } from "@/router/router-constants/router-params";
|
import { routerParams } from "@/router/router-constants/router-params";
|
||||||
|
|
@ -106,7 +106,7 @@ export function setupCookies({ funnelCookieValue = "", includeHeritageCookie = t
|
||||||
Object.keys(cookies).forEach(key => {
|
Object.keys(cookies).forEach(key => {
|
||||||
const cookieValue = key == cookieNames.FUNNEL_SESSION_INFO ? funnelCookieValue : cookies[key];
|
const cookieValue = key == cookieNames.FUNNEL_SESSION_INFO ? funnelCookieValue : cookies[key];
|
||||||
if (includeHeritageCookie || key != cookieNames.FUNNEL_SESSION_INFO)
|
if (includeHeritageCookie || key != cookieNames.FUNNEL_SESSION_INFO)
|
||||||
document.cookie = `${key}=${cookieValue}; path=/; ${getCookieDomainValue()}`;
|
setCookieProperties({ [key]: cookieValue }, { isSecure: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage=false />
|
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage=false />
|
||||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
<div class="fade-on-route-transition sub-container make-tall">
|
<div class="fade-on-route-transition sub-container make-tall">
|
||||||
<h1>CAPABILITY QUESTIONS TEMPORARY PLACEHOLDER</h1>
|
|
||||||
<alert
|
<alert
|
||||||
ref="alertFewMoreQuestions"
|
ref="alertFewMoreQuestions"
|
||||||
class="my-5"
|
class="my-5"
|
||||||
|
|
@ -20,16 +19,13 @@
|
||||||
:manualCopy="AlertFewMoreQuestionsCopy"
|
:manualCopy="AlertFewMoreQuestionsCopy"
|
||||||
v-bind:isDismissible="false"
|
v-bind:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
<div v-for="(part, i) in capabilityQuestionsData" :key="i">
|
<questionChain
|
||||||
<questionChain
|
ref="questionChain"
|
||||||
ref="questionChain"
|
v-model="selectedAnswer"
|
||||||
v-model="selectedModel"
|
:questionData="capabilityQuestionsData"
|
||||||
:questionData="part"
|
:partIndex="i"
|
||||||
:partIndex="i"
|
validationRules="questions-required"
|
||||||
v-if="showThisPartQuestionChain(part, i)"
|
/>
|
||||||
validationRules="questions-required"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<funnel-footer
|
<funnel-footer
|
||||||
ref="funnelFooter"
|
ref="funnelFooter"
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
|
@ -57,17 +53,19 @@ import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
|
||||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
import { Form, defineRule } from "vee-validate";
|
import { Form, defineRule } from "vee-validate";
|
||||||
import { required } from "@/helpers/validation-rules";
|
import { required } from "@/helpers/validation-rules";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||||
|
import { damageLocationsSelected } from "@/constants/damage-locations-selected";
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "capability-questions",
|
name: "capability-questions",
|
||||||
|
mixins: [vehicleQuestionsMixin],
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
|
|
@ -89,55 +87,51 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedModel: [],
|
selectedAnswer: [],
|
||||||
partsQuestionsData: this.$store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS).partsOrQuestions.filter((p) => {
|
// TODO This shouldn't be an object with property `partQuestions`
|
||||||
if (Array.isArray(p.partQuestions) && p.partQuestions.length > 0) {
|
capabilityQuestionsData: {
|
||||||
return {
|
partQuestions: store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS).capabilityQuestions
|
||||||
glassName: p.glassName,
|
}
|
||||||
glassLocation: p.glassLocation,
|
|
||||||
partQuestions: p.partQuestions,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
currentPartNum: 0,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
AlertFewMoreQuestionsHeader() {
|
AlertFewMoreQuestionsHeader() {
|
||||||
return this.getCmsContent("AlertPartsQuestions", "HeadlineText");
|
return this.getCmsContent("AdditionalPartsQuestionsAlert", "HeadlineText");
|
||||||
},
|
},
|
||||||
AlertFewMoreQuestionsCopy() {
|
AlertFewMoreQuestionsCopy() {
|
||||||
return this.getCmsContent("AlertPartsQuestions", "BodyText");
|
return this.getCmsContent("AdditionalPartsQuestionsAlert", "BodyText");
|
||||||
},
|
},
|
||||||
|
windshieldPart() {
|
||||||
|
return this.pageData.partsOrQuestions.find(x => x.glassLocation === damageLocationsSelected.WINDSHIELD);
|
||||||
|
},
|
||||||
|
windshieldPartInfo() {
|
||||||
|
return this.windshieldPart.parts[0];
|
||||||
|
},
|
||||||
|
pageData() {
|
||||||
|
return this.$store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
return false; // TODO - DO TRUE TEST OF PAGEDATA
|
const capabilityQuestionsPageData = store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS);
|
||||||
// return Object.keys(store.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)).length > 0;
|
return capabilityQuestionsPageData && Object.keys(capabilityQuestionsPageData).length > 0;
|
||||||
},
|
|
||||||
showThisPartQuestionChain(part, i) {
|
|
||||||
if (part.partQuestions?.length < 1) { return false; } // return false if only one partQuestion
|
|
||||||
if (this.currentPartNum === i || part.answerData?.answerResult.length > 0) { return true; }
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
backButtonAction() {
|
|
||||||
// route to move backwards
|
|
||||||
this.$router.navigateWithoutSaving(
|
|
||||||
this.navigationScenarios.CLICKED_BACK,
|
|
||||||
this.$route
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
// TODO: TO COME
|
const selectedAnswerResult1 = this.selectedAnswer.answerResult;
|
||||||
},
|
const selectedAnswerResult2 = this.pageData.capabilityQuestions[0].answers.find(x => x.answerResult1 === selectedAnswerResult1).answerResult2;
|
||||||
},
|
|
||||||
watch: {
|
this.dispatchStoreAction(storeActions.SAVE_CAPABILITY_QUESTION_ANSWERS, {
|
||||||
selectedModel(model) {
|
glassName: this.windshieldPart.glassName,
|
||||||
this.capabilityQuestionsData[model.partIndex].answerData = {
|
glassLocation: this.windshieldPart.glassLocation,
|
||||||
answerResult: model.answerResult,
|
result1: selectedAnswerResult1,
|
||||||
answeredQuestions: model.answeredQuestions,
|
result2: selectedAnswerResult2
|
||||||
}
|
});
|
||||||
this.currentPartNum = model.partIndex + 1;
|
|
||||||
|
const partFromCapabilityQuestionAnswer = (await this.dispatchStoreAction(storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER)).data;
|
||||||
|
let partsOrQuestions = this.pageData.partsOrQuestions;
|
||||||
|
partsOrQuestions.find(partOrQuestion => partOrQuestion.glassLocation === damageLocationsSelected.WINDSHIELD).parts = partFromCapabilityQuestionAnswer;
|
||||||
|
|
||||||
|
this.navigateForward(partsOrQuestions);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,9 @@
|
||||||
<questionChain
|
<questionChain
|
||||||
ref="questionChain"
|
ref="questionChain"
|
||||||
:key="part.key"
|
:key="part.key"
|
||||||
v-model="selectedAnswer"
|
:keyString="part.key"
|
||||||
:questionData="part"
|
v-model="selectedAnswers[part.glassLocation + '-' + part.glassName]"
|
||||||
|
:questionData="part.partQuestions"
|
||||||
:partIndex="i"
|
:partIndex="i"
|
||||||
v-if="showThisPartQuestionChain(part, i)"
|
v-if="showThisPartQuestionChain(part, i)"
|
||||||
validationRules="questions-required"
|
validationRules="questions-required"
|
||||||
|
|
@ -95,7 +96,7 @@ export default {
|
||||||
partsQuestionsFromApi: this.$store.getters.pageData(fmgPageValues.PART_QUESTIONS)?.partsOrQuestions.filter((p) => {
|
partsQuestionsFromApi: this.$store.getters.pageData(fmgPageValues.PART_QUESTIONS)?.partsOrQuestions.filter((p) => {
|
||||||
return Array.isArray(p.partQuestions) && p.partQuestions.length > 0;
|
return Array.isArray(p.partQuestions) && p.partQuestions.length > 0;
|
||||||
}),
|
}),
|
||||||
selectedAnswer: [],
|
selectedAnswers: {},
|
||||||
currentPartNum: 0,
|
currentPartNum: 0,
|
||||||
newAnswersArray: [],
|
newAnswersArray: [],
|
||||||
partsQuestionsData: [],
|
partsQuestionsData: [],
|
||||||
|
|
@ -112,24 +113,14 @@ export default {
|
||||||
},
|
},
|
||||||
mixins: [vehicleQuestionsMixin],
|
mixins: [vehicleQuestionsMixin],
|
||||||
mounted() {
|
mounted() {
|
||||||
this.partsQuestionsData = this.partsQuestionsFromApi.map((part, i) => {
|
this.LoadInitialPartsData();
|
||||||
part.key = part.glassLocation + part.glassName;
|
|
||||||
return part;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showThisPartQuestionChain(part, i) {
|
showThisPartQuestionChain(part, i) {
|
||||||
if (part.partQuestions?.length < 1 || part.suppressPart) { return false; } // return false if no partQuestions or if suppressed
|
if (part.partQuestions?.length < 1 || part.isSuppressedPart) { return false; } // return false if no partQuestions or if suppressed
|
||||||
if (this.currentPartNum === i || part.answerData?.answerResult?.length > 0) { return true; }
|
if (this.currentPartNum === i || part.answerData?.answerResult?.length > 0) { return true; }
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
backButtonAction() {
|
|
||||||
// route to move backwards
|
|
||||||
this.$router.navigateWithoutSaving(
|
|
||||||
this.navigationScenarios.CLICKED_BACK,
|
|
||||||
this.$route
|
|
||||||
);
|
|
||||||
},
|
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
const partQuestionAnswersArray = this.partsQuestionsData.map((item) => {
|
const partQuestionAnswersArray = this.partsQuestionsData.map((item) => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -137,6 +128,7 @@ export default {
|
||||||
glassName: item.glassName,
|
glassName: item.glassName,
|
||||||
result: item.answerData.answerResult,
|
result: item.answerData.answerResult,
|
||||||
answeredQuestions: item.answerData.answeredQuestions,
|
answeredQuestions: item.answerData.answeredQuestions,
|
||||||
|
isSuppressedPart: item.isSuppressedPart,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -155,51 +147,28 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
const glassNameAndPartsForStore = partsLookup.data.glassNameAndParts;
|
const glassNameAndPartsForStore = partsLookup.data.glassNameAndParts;
|
||||||
const hasGlassLocationWithMultipleParts = this.hasGlassLocationWithMultipleParts(glassNameAndPartsForStore);
|
this.navigateForward(glassNameAndPartsForStore);
|
||||||
const hasChildPartQuestions = this.hasChildPartQuestions(glassNameAndPartsForStore);
|
|
||||||
const hasCapabilityQuestions = this.hasCapabilityQuestions(glassNameAndPartsForStore);
|
|
||||||
|
|
||||||
// NAVIGATE FORWARD
|
|
||||||
if (hasGlassLocationWithMultipleParts) {
|
|
||||||
// if multiple parts on any glass
|
|
||||||
// go to vehicle-parts page and pass the partsData
|
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS,this.$route,{},{},{partsOrQuestions: glassNameAndPartsForStore});
|
|
||||||
} else if (hasChildPartQuestions) {
|
|
||||||
// if any childpart questions
|
|
||||||
// go to molding-questions page and pass the partsData
|
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.HAS_MOLDING_QUESTIONS,this.$route,{},{},{partsOrQuestions: glassNameAndPartsForStore});
|
|
||||||
} else if (hasCapabilityQuestions) {
|
|
||||||
// if has capability questions
|
|
||||||
// go to capability-questions page and pass the partsData
|
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.HAS_CAPABILITY_QUESTIONS,this.$route,{},{},{partsOrQuestions: glassNameAndPartsForStore});
|
|
||||||
} else {
|
|
||||||
// if single parts only
|
|
||||||
const collectedGlassParts = this.reducedGlassPartsArray(glassNameAndPartsForStore);
|
|
||||||
// save to store lineItems.glassParts
|
|
||||||
this.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts);
|
|
||||||
// go to heritage quote page
|
|
||||||
this.$refs.loadingModal.showModal();
|
|
||||||
navigateToHeritageFunnel();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
const partQuestionsFromPageData = store.getters.pageData(fmgPageValues.PART_QUESTIONS);
|
const partQuestionsFromPageData = store.getters.pageData(fmgPageValues.PART_QUESTIONS);
|
||||||
return partQuestionsFromPageData && Object.keys(partQuestionsFromPageData).length > 0;
|
return partQuestionsFromPageData && Object.keys(partQuestionsFromPageData).length > 0;
|
||||||
},
|
},
|
||||||
},
|
handleAnswerUpdates(key, answer) { // only runs when all questions in a question-chain have been answered
|
||||||
watch: {
|
// when selectedAnswers updates, user has completed this part's question chain and has a final answer
|
||||||
selectedAnswer(answer) {
|
|
||||||
// when selectedAnswer updates, user has completed this part's question chain and has a final answer
|
|
||||||
// (does not get run for each invididual question's answer, only when
|
// (does not get run for each invididual question's answer, only when
|
||||||
// all relevent questions for the current part have been answered)
|
// all relevent questions for the current part have been answered)
|
||||||
const glassPart = this.partsQuestionsData[answer.partIndex];
|
const glassPartWithAnswer = this.partsQuestionsData[answer.partIndex];
|
||||||
const completeAnsweredQuestions = [...answer.answeredQuestions];
|
const completeAnsweredQuestions = answer.answeredQuestions ? [...answer.answeredQuestions] : [];
|
||||||
const answeredQuestionIndexes = [];
|
const answeredQuestionIndexes = [];
|
||||||
|
|
||||||
|
// since user has answered a question differently than anything that was preloaded,
|
||||||
|
// then clear out the preloaded answers
|
||||||
|
this.selectedAnswers = {};
|
||||||
|
|
||||||
// examine all the answers returned that were part of the user's journey through question-chain
|
// examine all the answers returned that were part of the user's journey through question-chain
|
||||||
|
|
||||||
// loop through every answered question on currently answered glass part
|
// loop through every answered question on currently answered glass part
|
||||||
answer.answeredQuestions.forEach((aq) => {
|
answer.answeredQuestions?.forEach((aq) => {
|
||||||
|
|
||||||
// gather all the question numbers of the answered questions
|
// gather all the question numbers of the answered questions
|
||||||
answeredQuestionIndexes.push(aq.questionNum);
|
answeredQuestionIndexes.push(aq.questionNum);
|
||||||
|
|
@ -216,14 +185,18 @@ export default {
|
||||||
|
|
||||||
// loop through this glass part's part questions, looking for a questionText match
|
// loop through this glass part's part questions, looking for a questionText match
|
||||||
glassPart.partQuestions.forEach((pq, pqIndex) => {
|
glassPart.partQuestions.forEach((pq, pqIndex) => {
|
||||||
// does pq.questionText match answeredQuestionText? (do we have a duplicate question?)
|
// clear out any previously set answers
|
||||||
|
//delete pq.answerSelected;
|
||||||
|
pq.answerSelected = null;
|
||||||
|
|
||||||
|
// does pq.questionText match answeredQuestionText? (aka do we have a duplicate question?)
|
||||||
if (pq.questionText.toUpperCase() === answeredQuestionText) {
|
if (pq.questionText.toUpperCase() === answeredQuestionText) {
|
||||||
// which one of this partQuestions' answers matches our answer?
|
|
||||||
|
|
||||||
|
// which one of this partQuestions' answers matches our answer?
|
||||||
let matchedAnswer;
|
let matchedAnswer;
|
||||||
pq.answers.forEach((ans, ansIndex) => {
|
pq.answers.forEach((ans, ansIndex) => {
|
||||||
delete pq.answers[ansIndex].selected;
|
// delete pq.answers[ansIndex].selected;
|
||||||
|
pq.answers[ansIndex].selected = null;
|
||||||
if (ans.answerText.toUpperCase() === answeredQuestionAnswer) {
|
if (ans.answerText.toUpperCase() === answeredQuestionAnswer) {
|
||||||
matchedAnswer = ans;
|
matchedAnswer = ans;
|
||||||
pq.answers[ansIndex].selected = true;
|
pq.answers[ansIndex].selected = true;
|
||||||
|
|
@ -234,8 +207,8 @@ export default {
|
||||||
const thisAnsweredPartQuestion = glassPart.partQuestions[pqIndex];
|
const thisAnsweredPartQuestion = glassPart.partQuestions[pqIndex];
|
||||||
|
|
||||||
// remove answerData from this glass part
|
// remove answerData from this glass part
|
||||||
delete glassPart.answerData;
|
glassPart.answerData = null;
|
||||||
delete glassPart.suppressPart;
|
glassPart.isSuppressedPart = null;
|
||||||
|
|
||||||
// Update the key to re-render this part's question-chain component
|
// Update the key to re-render this part's question-chain component
|
||||||
this.partsQuestionsData[i].key = this.partsQuestionsData[i].glassLocation + this.partsQuestionsData[i].glassName + Date.now().toString();
|
this.partsQuestionsData[i].key = this.partsQuestionsData[i].glassLocation + this.partsQuestionsData[i].glassName + Date.now().toString();
|
||||||
|
|
@ -246,11 +219,11 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (rejectedAnswer[0].nextQuestionSequence) {
|
if (rejectedAnswer[0].nextQuestionSequence) {
|
||||||
glassPart.partQuestions[rejectedAnswer[0].nextQuestionSequence - 1].suppressQuestion = true;
|
glassPart.partQuestions[rejectedAnswer[0].nextQuestionSequence - 1].suppressDuplicateQuestion = true;
|
||||||
}
|
}
|
||||||
if (matchedAnswer.nextQuestionSequence) {
|
if (matchedAnswer.nextQuestionSequence) {
|
||||||
// ensure that accepted answer is NOT suppressed
|
// ensure that accepted answer is NOT suppressed
|
||||||
delete glassPart.partQuestions[matchedAnswer.nextQuestionSequence - 1].suppressQuestion;
|
glassPart.partQuestions[matchedAnswer.nextQuestionSequence - 1].suppressDuplicateQuestion = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle suppressing upstream in this question chain
|
// handle suppressing upstream in this question chain
|
||||||
|
|
@ -260,11 +233,11 @@ export default {
|
||||||
if (thisAns.originalNextQuestionSequence === pq.questionSequence) {
|
if (thisAns.originalNextQuestionSequence === pq.questionSequence) {
|
||||||
// restore original nextQuestionSequence
|
// restore original nextQuestionSequence
|
||||||
thisAns.nextQuestionSequence = thisAns.originalNextQuestionSequence;
|
thisAns.nextQuestionSequence = thisAns.originalNextQuestionSequence;
|
||||||
delete thisAns.originalNextQuestionSequence;
|
this.originalNextQuestionSequence = null;
|
||||||
// restore original answerResult
|
// restore original answerResult
|
||||||
if (thisAns.originalAnswerResult) {
|
if (thisAns.originalAnswerResult) {
|
||||||
thisAns.answerResult = thisAns.originalAnswerResult;
|
thisAns.answerResult = thisAns.originalAnswerResult;
|
||||||
delete thisAns.originalAnswerResult;
|
thisAns.originalAnswerResult = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// search for any of the answers that lead to the duplicated question
|
// search for any of the answers that lead to the duplicated question
|
||||||
|
|
@ -284,7 +257,7 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
// suppress current question
|
// suppress current question
|
||||||
thisAnsweredPartQuestion.suppressQuestion = true;
|
thisAnsweredPartQuestion.suppressDuplicateQuestion = true;
|
||||||
|
|
||||||
const thisGlassPart = "glassPart" + i;
|
const thisGlassPart = "glassPart" + i;
|
||||||
if (this.foundDuplicateQuestions[thisGlassPart]) {
|
if (this.foundDuplicateQuestions[thisGlassPart]) {
|
||||||
|
|
@ -297,7 +270,7 @@ export default {
|
||||||
|
|
||||||
// are there any questions left that are not suppressed?
|
// are there any questions left that are not suppressed?
|
||||||
const remainingQuestions = glassPart.partQuestions.filter((q) => {
|
const remainingQuestions = glassPart.partQuestions.filter((q) => {
|
||||||
return !q.suppressQuestion;
|
return !q.suppressDuplicateQuestion;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (remainingQuestions.length < 1) {
|
if (remainingQuestions.length < 1) {
|
||||||
|
|
@ -308,6 +281,7 @@ export default {
|
||||||
questionText: pq.questionText,
|
questionText: pq.questionText,
|
||||||
selectedAnswerText: matchedAnswer.answerText,
|
selectedAnswerText: matchedAnswer.answerText,
|
||||||
questionNum: pq.questionSequence,
|
questionNum: pq.questionSequence,
|
||||||
|
isDuplicateQuestion: pq.suppressDuplicateQuestion,
|
||||||
};
|
};
|
||||||
// set the answerData as 'already answered'
|
// set the answerData as 'already answered'
|
||||||
glassPart.answerData = {
|
glassPart.answerData = {
|
||||||
|
|
@ -316,7 +290,7 @@ export default {
|
||||||
};
|
};
|
||||||
|
|
||||||
// suppress this glassPart because it has an answer
|
// suppress this glassPart because it has an answer
|
||||||
glassPart.suppressPart = true;
|
glassPart.isSuppressedPart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // END of if (matchedAnswer)
|
} // END of if (matchedAnswer)
|
||||||
|
|
@ -324,6 +298,10 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update the key to re-render this part's question-chain component
|
||||||
|
this.partsQuestionsData[i].key = this.partsQuestionsData[i].glassLocation + this.partsQuestionsData[i].glassName + Date.now().toString();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
@ -344,10 +322,10 @@ export default {
|
||||||
|
|
||||||
thisPartsDupes?.forEach((dupe) => {
|
thisPartsDupes?.forEach((dupe) => {
|
||||||
// dupe is a single integer
|
// dupe is a single integer
|
||||||
const dupeQuestion = glassPart.partQuestions[dupe - 1];
|
const dupeQuestion = glassPartWithAnswer.partQuestions[dupe - 1];
|
||||||
const dupeQuestionAnswer = dupeQuestion.answers.find((q) => q.selected === true);
|
const dupeQuestionAnswer = dupeQuestion.answers.find((q) => q.selected === true);
|
||||||
|
|
||||||
glassPart.partQuestions.forEach((q) => {
|
glassPartWithAnswer.partQuestions.forEach((q) => {
|
||||||
let includeThisDupeInAnsweredQuestions = false;
|
let includeThisDupeInAnsweredQuestions = false;
|
||||||
|
|
||||||
// did one of the answers of this question point to the duplicated question?
|
// did one of the answers of this question point to the duplicated question?
|
||||||
|
|
@ -359,7 +337,7 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// is this q.questionSequnce listed as the duplicated question's nextQuestionSequence?
|
// is this q.questionSequence listed as the duplicated question's nextQuestionSequence?
|
||||||
if ((q.questionSequence === dupeQuestionAnswer.nextQuestionSequence) && (answeredQuestionIndexes.includes(q.questionSequence))) {
|
if ((q.questionSequence === dupeQuestionAnswer.nextQuestionSequence) && (answeredQuestionIndexes.includes(q.questionSequence))) {
|
||||||
includeThisDupeInAnsweredQuestions = true;
|
includeThisDupeInAnsweredQuestions = true;
|
||||||
}
|
}
|
||||||
|
|
@ -369,12 +347,13 @@ export default {
|
||||||
questionNum: dupeQuestion.questionSequence,
|
questionNum: dupeQuestion.questionSequence,
|
||||||
questionText: dupeQuestion.questionText,
|
questionText: dupeQuestion.questionText,
|
||||||
selectedAnswerText: dupeQuestionAnswer.answerText,
|
selectedAnswerText: dupeQuestionAnswer.answerText,
|
||||||
|
isDuplicateQuestion: dupeQuestion.suppressDuplicateQuestion,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// make sure there are no duplicated dupes...
|
// make sure there are no duplicated dupes in the list...
|
||||||
const foundInCompleteAnsweredQuestions = new Set();
|
const foundInCompleteAnsweredQuestions = new Set();
|
||||||
let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => {
|
let filteredCompleteAnsweredQuestions = completeAnsweredQuestions.filter(el => {
|
||||||
const duplicate = foundInCompleteAnsweredQuestions.has(el.questionText);
|
const duplicate = foundInCompleteAnsweredQuestions.has(el.questionText);
|
||||||
|
|
@ -384,7 +363,7 @@ export default {
|
||||||
filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a,b) => a.questionNum - b.questionNum);
|
filteredCompleteAnsweredQuestions = filteredCompleteAnsweredQuestions.sort((a,b) => a.questionNum - b.questionNum);
|
||||||
|
|
||||||
// set final answer data for the current answered glass part
|
// set final answer data for the current answered glass part
|
||||||
glassPart.answerData = {
|
glassPartWithAnswer.answerData = {
|
||||||
answerResult: answer.answerResult,
|
answerResult: answer.answerResult,
|
||||||
answeredQuestions: filteredCompleteAnsweredQuestions,
|
answeredQuestions: filteredCompleteAnsweredQuestions,
|
||||||
}
|
}
|
||||||
|
|
@ -397,6 +376,68 @@ export default {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
LoadInitialPartsData() {
|
||||||
|
|
||||||
|
// are there alreadyAnsweredQuestions?
|
||||||
|
const alreadyAnsweredQuestions = store.getters.damage.partQuestionAnswers;
|
||||||
|
|
||||||
|
this.partsQuestionsData = this.partsQuestionsFromApi.map((part, i) => {
|
||||||
|
part.key = part.glassLocation + "-" + part.glassName;
|
||||||
|
this.selectedAnswers[part.key] = [];
|
||||||
|
|
||||||
|
alreadyAnsweredQuestions?.forEach((savedPart) => {
|
||||||
|
if (!savedPart.glassLocation || !savedPart.glassName || !savedPart.answeredQuestions || !savedPart.result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (part.glassLocation === savedPart.glassLocation && part.glassName === savedPart.glassName) {
|
||||||
|
let answerString = "";
|
||||||
|
|
||||||
|
// matches; loop through answeredQuestions for matches
|
||||||
|
savedPart.answeredQuestions.forEach((aq) => {
|
||||||
|
if (!aq.questionNum || !aq.selectedAnswerText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// determine which answer was previously chosen
|
||||||
|
const theAns = part.partQuestions[aq.questionNum-1].answers.find((a) => {
|
||||||
|
return a.answerText.toUpperCase() === aq.selectedAnswerText.toUpperCase();
|
||||||
|
});
|
||||||
|
if (theAns.nextQuestionSequence) {
|
||||||
|
answerString = `${aq.questionNum}|nextQuestion|${theAns.nextQuestionSequence}|${theAns.answerText}`
|
||||||
|
} else {
|
||||||
|
answerString = `${aq.questionNum}|answer|${theAns.answerResult}|${theAns.answerText}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark this partQuestion as answered (question-chain will read this)
|
||||||
|
part.partQuestions[aq.questionNum-1].answerSelected = answerString;
|
||||||
|
// mark this partQuestion as duplicate if it is (question-chain will read this)
|
||||||
|
if (aq.isDuplicateQuestion) {
|
||||||
|
part.partQuestions[aq.questionNum-1].isDuplicateQuestion = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// advance the currentPartNum
|
||||||
|
this.currentPartNum = i;
|
||||||
|
|
||||||
|
// add answerData to current part
|
||||||
|
part.answerData = {
|
||||||
|
answerResult: savedPart.result,
|
||||||
|
answeredQuestions: savedPart.answeredQuestions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up watch for each set of part questions, which gets updated when all questions for a part have been answered
|
||||||
|
this.$watch("selectedAnswers." + part.key, (newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
this.handleAnswerUpdates(part.key, newValue);
|
||||||
|
}
|
||||||
|
}, {deep: true})
|
||||||
|
|
||||||
|
return part;
|
||||||
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="windshield-options">
|
<div class="windshield-options">
|
||||||
<windshieldDamageTypeQuestion cmsWidgetName="WindshieldDamageTypeQuestion"
|
<windshieldDamageTypeQuestion cmsWidgetName="WindshieldDamageTypeQuestion"
|
||||||
:isAvailable=isWindshieldDamageLocation
|
:isAvailable="isWindshieldDamageLocation"
|
||||||
:suppressError="hasRepairReplaceConflict || showNoReplacementAvailableError"
|
:suppressError="hasRepairReplaceConflict || showNoReplacementAvailableError"
|
||||||
groupName="WindshieldDamageTypeQuestion"
|
groupName="WindshieldDamageTypeQuestion"
|
||||||
v-model="selectedWindshieldDamageTypeValue"
|
v-model="selectedWindshieldDamageTypeValue"
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
cmsWidgetName="NoReplacementAvailableError"
|
cmsWidgetName="NoReplacementAvailableError"
|
||||||
alertClass="alert-danger"
|
alertClass="alert-danger"
|
||||||
:isDismissible="false"
|
:isDismissible="false"
|
||||||
/>
|
/>
|
||||||
<windshieldChipCountQuestion cmsWidgetName="WindshieldChipCountQuestion"
|
<windshieldChipCountQuestion cmsWidgetName="WindshieldChipCountQuestion"
|
||||||
:isAvailable="isRepairOptionSelected && !hasRepairReplaceConflict"
|
:isAvailable="isRepairOptionSelected && !hasRepairReplaceConflict"
|
||||||
groupName="WindshieldChipCountQuestion"
|
groupName="WindshieldChipCountQuestion"
|
||||||
|
|
@ -137,15 +137,16 @@ export default ({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isWindshieldDamageLocation() {
|
isWindshieldDamageLocation() {
|
||||||
return this.selectedDamageLocations.some(selectedDamages =>
|
return this.selectedDamageLocations.some(selectedDamageLocation => selectedDamageLocation === damageLocationsSelected.WINDSHIELD);
|
||||||
{
|
|
||||||
return Boolean(selectedDamages.toUpperCase() === "WINDSHIELD");
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
isRepairOptionSelected(){
|
isRepairOptionSelected(){
|
||||||
|
if (!this.selectedWindshieldDamageTypeValue) return false;
|
||||||
|
|
||||||
return this.selectedWindshieldDamageTypeValue === damageLocationsSelected.REPAIR && this.isWindshieldDamageLocation;
|
return this.selectedWindshieldDamageTypeValue === damageLocationsSelected.REPAIR && this.isWindshieldDamageLocation;
|
||||||
},
|
},
|
||||||
isReplaceOptionSelected(){
|
isReplaceOptionSelected(){
|
||||||
|
if (!this.selectedWindshieldDamageTypeValue) return false;
|
||||||
|
|
||||||
return this.selectedWindshieldDamageTypeValue === damageLocationsSelected.REPLACE && this.isWindshieldDamageLocation;
|
return this.selectedWindshieldDamageTypeValue === damageLocationsSelected.REPLACE && this.isWindshieldDamageLocation;
|
||||||
},
|
},
|
||||||
isWindshieldReplaceAvailable() {
|
isWindshieldReplaceAvailable() {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { shallowMount } from "@vue/test-utils";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
|
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
|
||||||
|
|
@ -235,7 +236,7 @@ describe("vehicle-parts.vue", () => {
|
||||||
wrapper.vm.backButtonAction();
|
wrapper.vm.backButtonAction();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITH_PART_QUESTION_ANSWERS, wrapper.vm.$route);
|
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS, wrapper.vm.$route);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -276,7 +277,7 @@ describe("vehicle-parts.vue", () => {
|
||||||
wrapper.vm.backButtonAction();
|
wrapper.vm.backButtonAction();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS, wrapper.vm.$route);
|
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP, wrapper.vm.$route);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -321,6 +322,7 @@ describe("vehicle-parts.vue", () => {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
store.getters.lineItems = { glassParts: {} }
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
mountOptionsMockData: {
|
mountOptionsMockData: {
|
||||||
|
|
@ -379,6 +381,8 @@ describe("vehicle-parts.vue", () => {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
store.getters.lineItems = { glassParts: {} }
|
||||||
|
store.getters.vehicle = { carId: "TEST_CAR_ID" }
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
mountOptionsMockData: {
|
mountOptionsMockData: {
|
||||||
|
|
@ -396,6 +400,12 @@ describe("vehicle-parts.vue", () => {
|
||||||
getters: store.getters,
|
getters: store.getters,
|
||||||
commit: store.commit
|
commit: store.commit
|
||||||
},
|
},
|
||||||
|
actionList: [
|
||||||
|
{
|
||||||
|
actionName: storeActions.GET_CAPABILITY_QUESTIONS,
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -420,6 +430,7 @@ describe("vehicle-parts.vue", () => {
|
||||||
//Arrange
|
//Arrange
|
||||||
store.getters.pageData.mockReturnValueOnce(basePartResponse);
|
store.getters.pageData.mockReturnValueOnce(basePartResponse);
|
||||||
store.getters.lineItems = { glassParts: {} }
|
store.getters.lineItems = { glassParts: {} }
|
||||||
|
store.getters.vehicle = { carId: "TEST_CAR_ID" }
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
mountOptionsMockData: {
|
mountOptionsMockData: {
|
||||||
|
|
|
||||||
|
|
@ -132,8 +132,8 @@ export default {
|
||||||
ColorAnswerText: p.color,
|
ColorAnswerText: p.color,
|
||||||
FeatureAnswers: [
|
FeatureAnswers: [
|
||||||
{
|
{
|
||||||
FeatureAnswerText: p.description === "" ? p.color : p.description,
|
FeatureAnswerText: p.description === "" ? p.color : p.description,
|
||||||
PartNumber: p.partNumber,
|
PartNumber: p.partNumber,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
@ -159,15 +159,6 @@ export default {
|
||||||
return store.getters.damage.isRepair != null && store.getters.pageData(fmgPageValues.VEHICLE_PARTS) &&
|
return store.getters.damage.isRepair != null && store.getters.pageData(fmgPageValues.VEHICLE_PARTS) &&
|
||||||
Object.keys(store.getters.pageData(fmgPageValues.VEHICLE_PARTS)).length !== 0;
|
Object.keys(store.getters.pageData(fmgPageValues.VEHICLE_PARTS)).length !== 0;
|
||||||
},
|
},
|
||||||
backButtonAction() {
|
|
||||||
const hasPartQuestions = this.hasPartQuestions(this.$store.getters.pageData(fmgPageValues.PART_QUESTIONS)?.partsOrQuestions);
|
|
||||||
const backNavigationScenario = hasPartQuestions ? this.navigationScenarios.CLICKED_BACK_WITH_PART_QUESTION_ANSWERS : this.navigationScenarios.CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS;
|
|
||||||
|
|
||||||
this.$router.navigateWithoutSaving(
|
|
||||||
backNavigationScenario,
|
|
||||||
this.$route
|
|
||||||
);
|
|
||||||
},
|
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
const matchedParts = [];
|
const matchedParts = [];
|
||||||
|
|
||||||
|
|
@ -191,10 +182,6 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasChildPartQuestions = this.hasChildPartQuestions(matchedParts);
|
|
||||||
const hasCapabilityQuestions = this.hasCapabilityQuestions(matchedParts);
|
|
||||||
|
|
||||||
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
|
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
|
||||||
if (this.isForwardActionDisabled) {
|
if (this.isForwardActionDisabled) {
|
||||||
this.$refs.funnelFooter.removeLoader();
|
this.$refs.funnelFooter.removeLoader();
|
||||||
|
|
@ -202,33 +189,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigate to the next page
|
// Navigate to the next page
|
||||||
if (hasChildPartQuestions) {
|
this.navigateForward(matchedParts);
|
||||||
this.$router.navigateWithSaving(
|
|
||||||
this.navigationScenarios.HAS_MOLDING_QUESTIONS,
|
|
||||||
this.$route,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{partsOrQuestions: matchedParts}
|
|
||||||
);
|
|
||||||
} else if (hasCapabilityQuestions) {
|
|
||||||
this.$router.navigateWithSaving(
|
|
||||||
this.navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
|
||||||
this.$route,
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{partsOrQuestions: matchedParts}
|
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// if single parts only
|
|
||||||
const collectedGlassParts = this.reducedGlassPartsArray(matchedParts);
|
|
||||||
// save to store lineItems.glassParts
|
|
||||||
this.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts);
|
|
||||||
|
|
||||||
// go to heritage quote page
|
|
||||||
this.$refs.loadingModal.showModal();
|
|
||||||
navigateToHeritageFunnel();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
LoadInitialPartsData() {
|
LoadInitialPartsData() {
|
||||||
|
|
|
||||||
|
|
@ -51,14 +51,17 @@ export default {
|
||||||
|
|
||||||
const experimentForLogging = store.getters.applicationUser.experiments.find(e => e.universeName === experimentUniverses.CONCEPT_FUNNEL);
|
const experimentForLogging = store.getters.applicationUser.experiments.find(e => e.universeName === experimentUniverses.CONCEPT_FUNNEL);
|
||||||
|
|
||||||
// Log experiment exposure
|
// If the concept funnel experiment is found, as it should be when coming from safelite.com, then log the experiment exposure.
|
||||||
baseMixin.methods.dispatchStoreAction(storeActions.LOG_EXPERIMENT_EXPOSURE,
|
if (experimentForLogging !== undefined) {
|
||||||
{
|
// Log experiment exposure
|
||||||
userId: getDeviceIdValue(),
|
baseMixin.methods.dispatchStoreAction(storeActions.LOG_EXPERIMENT_EXPOSURE,
|
||||||
sessionKey: getSessionKeyValue(),
|
{
|
||||||
pageName: to.query.fmgPage,
|
userId: getDeviceIdValue(),
|
||||||
experiment: experimentForLogging
|
sessionKey: getSessionKeyValue(),
|
||||||
}, false);
|
pageName: to.query.fmgPage,
|
||||||
|
experiment: experimentForLogging
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Settle promises and get results
|
// Settle promises and get results
|
||||||
const promiseResultMap = [
|
const promiseResultMap = [
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ export default {
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
transition: all 250ms ease-in;
|
transition: all 250ms ease-in;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.vin-info {
|
.vin-info {
|
||||||
|
|
@ -86,6 +87,7 @@ export default {
|
||||||
transition: all 250ms ease-out;
|
transition: all 250ms ease-out;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
p {
|
p {
|
||||||
margin-bottom: .5rem;
|
margin-bottom: .5rem;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,14 @@ export default {
|
||||||
|
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
if (response.data.sessionKey && skey === 0) {
|
if (response.data.sessionKey && skey === 0) {
|
||||||
setCookieProperties({ [cookieNames.SESSION_KEY]: response.data.sessionKey});
|
setCookieProperties({ [cookieNames.SESSION_KEY]: response.data.sessionKey}, {
|
||||||
|
useDefaultFunnelCookieAttributes: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (response.data.sessionId && sid === '00000000-0000-0000-0000-000000000000') {
|
if (response.data.sessionId && sid === '00000000-0000-0000-0000-000000000000') {
|
||||||
setCookieProperties({ [cookieNames.SESSION_ID]: response.data.sessionId});
|
setCookieProperties({ [cookieNames.SESSION_ID]: response.data.sessionId}, {
|
||||||
|
maxAge: 60 * 30 // 30 minutes
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
export default {
|
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||||
|
import { storeMutations } from "@/constants/store-mutations.js";
|
||||||
|
import { damageLocationsSelected } from "@/constants/damage-locations-selected";
|
||||||
|
import { navigationScenarios } from "../router/router-constants/navigation-scenarios";
|
||||||
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
hasPartQuestions(partsOrQuestions) {
|
hasPartQuestions(partsOrQuestions) {
|
||||||
return partsOrQuestions?.some(pq => pq.partQuestions?.length > 0);
|
return partsOrQuestions?.some(pq => pq.partQuestions?.length > 0);
|
||||||
|
|
@ -17,6 +25,7 @@ export default {
|
||||||
return pq.parts?.some(part => part.requiresCapabilityQuestions === true);
|
return pq.parts?.some(part => part.requiresCapabilityQuestions === true);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// method to only include keys listed for lineItems.glassParts in
|
// method to only include keys listed for lineItems.glassParts in
|
||||||
// https://safelite.atlassian.net/wiki/spaces/DC/pages/17137665/Catalog+Front-End+State#glassParts
|
// https://safelite.atlassian.net/wiki/spaces/DC/pages/17137665/Catalog+Front-End+State#glassParts
|
||||||
reducedGlassPartsArray(glassParts) {
|
reducedGlassPartsArray(glassParts) {
|
||||||
|
|
@ -37,7 +46,103 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return reducedGlassParts;
|
return reducedGlassParts;
|
||||||
|
},
|
||||||
|
comparePageIndices(currentPage, fmgPage) {
|
||||||
|
const orderedVehicleQuestionPages = [
|
||||||
|
fmgPageValues.PART_QUESTIONS,
|
||||||
|
fmgPageValues.VEHICLE_PARTS,
|
||||||
|
fmgPageValues.MOLDING_QUESTIONS,
|
||||||
|
fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
|
fmgPageValues.QUOTE
|
||||||
|
]
|
||||||
|
|
||||||
|
return orderedVehicleQuestionPages.indexOf(currentPage) - orderedVehicleQuestionPages.indexOf(fmgPage);
|
||||||
|
},
|
||||||
|
currentPageComesBeforePage(currentPage = this.$route.query.fmgPage, fmgPage) {
|
||||||
|
return this.comparePageIndices(currentPage, fmgPage) < 0;
|
||||||
|
},
|
||||||
|
currentPageComesAfterPage(currentPage = this.$route.query.fmgPage, fmgPage) {
|
||||||
|
return this.comparePageIndices(currentPage, fmgPage) > 0;
|
||||||
|
},
|
||||||
|
// Can't use `this` because navigateForward is also called from vin-pages-mixin
|
||||||
|
async navigateForward(partsOrQuestions, vm) {
|
||||||
|
const self = vm ?? this;
|
||||||
|
const currentPage = self.$route.query.fmgPage;
|
||||||
|
|
||||||
|
const hasPartQuestions = this.hasPartQuestions(partsOrQuestions)
|
||||||
|
const hasGlassLocationWithMultipleParts = this.hasGlassLocationWithMultipleParts(partsOrQuestions);
|
||||||
|
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
|
||||||
|
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
|
||||||
|
|
||||||
|
if (hasPartQuestions && this.currentPageComesBeforePage(currentPage, fmgPageValues.PART_QUESTIONS)) {
|
||||||
|
self.$router.navigateWithSaving(self.navigationScenarios.HAS_PART_QUESTIONS, self.$route, {}, {}, {partsOrQuestions: partsOrQuestions});
|
||||||
|
}
|
||||||
|
else if (hasGlassLocationWithMultipleParts && this.currentPageComesBeforePage(currentPage, fmgPageValues.VEHICLE_PARTS)) {
|
||||||
|
// if multiple parts on any glass
|
||||||
|
// go to vehicle-parts page and pass the partsData
|
||||||
|
self.$router.navigateWithSaving(self.navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,self.$route,{},{},{partsOrQuestions: partsOrQuestions});
|
||||||
|
} else if (hasChildPartQuestions && this.currentPageComesBeforePage(currentPage, fmgPageValues.MOLDING_QUESTIONS)) {
|
||||||
|
// if any childpart questions
|
||||||
|
// go to molding-questions page and pass the partsData
|
||||||
|
self.$router.navigateWithSaving(self.navigationScenarios.HAS_MOLDING_QUESTIONS,self.$route,{},{},{partsOrQuestions: partsOrQuestions});
|
||||||
|
} else if (hasCapabilityQuestions && this.currentPageComesBeforePage(currentPage, fmgPageValues.CAPABILITY_QUESTIONS)) {
|
||||||
|
// if has capability questions
|
||||||
|
// go to capability-questions page and pass the partsData
|
||||||
|
const windshieldPart = partsOrQuestions.filter(x => x.glassLocation === damageLocationsSelected.WINDSHIELD)[0].parts[0];
|
||||||
|
let capabilityQuestions = (await baseMixin.methods.dispatchStoreAction(storeActions.GET_CAPABILITY_QUESTIONS, {
|
||||||
|
carId: store.getters.vehicle.carId,
|
||||||
|
partNumber: windshieldPart.partNumber
|
||||||
|
})).data;
|
||||||
|
|
||||||
|
capabilityQuestions.forEach(question => {
|
||||||
|
question.answers = question.answers.map(answer => {
|
||||||
|
return {
|
||||||
|
...answer,
|
||||||
|
answerResult: answer.answerResult1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
self.$router.navigateWithSaving(self.navigationScenarios.HAS_CAPABILITY_QUESTIONS, self.$route, {}, {}, { partsOrQuestions, capabilityQuestions });
|
||||||
|
} else {
|
||||||
|
// if single parts only
|
||||||
|
const collectedGlassParts = this.reducedGlassPartsArray(partsOrQuestions);
|
||||||
|
// save to store lineItems.glassParts
|
||||||
|
self.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts);
|
||||||
|
|
||||||
|
self.$refs.loadingModal.showModal();
|
||||||
|
navigateToHeritageFunnel();
|
||||||
|
|
||||||
|
// For quote pages MVP release
|
||||||
|
// self.$router.navigate(self.navigationScenarios.HAS_NO_MORE_QUESTIONS, self.$route);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
backButtonAction() {
|
||||||
|
const partsOrQuestions = this.$store.getters.pageData(fmgPageValues.PART_QUESTIONS)?.partsOrQuestions;
|
||||||
|
const hasPartQuestions = this.hasPartQuestions(partsOrQuestions);
|
||||||
|
const hasGlassLocationWithMultipleParts = this.hasGlassLocationWithMultipleParts(partsOrQuestions);
|
||||||
|
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
|
||||||
|
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
|
||||||
|
let backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP;
|
||||||
|
|
||||||
|
const currentPage = this.$route.query.fmgPage;
|
||||||
|
if (hasCapabilityQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.CAPABILITY_QUESTIONS)) {
|
||||||
|
backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_CAPABILITY_QUESTIONS;
|
||||||
|
}
|
||||||
|
else if (hasChildPartQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.MOLDING_QUESTIONS)) {
|
||||||
|
backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS;
|
||||||
|
}
|
||||||
|
else if (hasGlassLocationWithMultipleParts && this.currentPageComesAfterPage(currentPage, fmgPageValues.VEHICLE_PARTS)) {
|
||||||
|
backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS;
|
||||||
|
}
|
||||||
|
else if (hasPartQuestions && this.currentPageComesAfterPage(currentPage, fmgPageValues.PART_QUESTIONS)) {
|
||||||
|
backNavigationScenario = navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
backNavigationScenario,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,43 +1,13 @@
|
||||||
import { storeActions } from "@/constants/store-actions.js";
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
import { storeMutations } from "@/constants/store-mutations.js";
|
|
||||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
|
||||||
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [vehicleQuestionsMixin],
|
|
||||||
methods: {
|
methods: {
|
||||||
async navigateForwardWithSingleCarMatch() {
|
async navigateForwardWithSingleCarMatch() {
|
||||||
const result = await this.dispatchStoreAction(storeActions.GET_PARTS_OR_QUESTIONS);
|
const result = await this.dispatchStoreAction(storeActions.GET_PARTS_OR_QUESTIONS);
|
||||||
|
|
||||||
const partsOrQuestions = result.data.partsOrQuestions;
|
const partsOrQuestions = result.data.partsOrQuestions;
|
||||||
|
|
||||||
const hasPartsQuestions = this.hasPartQuestions(partsOrQuestions);
|
vehicleQuestionsMixin.methods.navigateForward(partsOrQuestions, this);
|
||||||
const hasGlassLocationWithMultipleParts = this.hasGlassLocationWithMultipleParts(partsOrQuestions);
|
|
||||||
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
|
|
||||||
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
|
|
||||||
|
|
||||||
if (hasPartsQuestions) {
|
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, this.$route, {}, {}, result.data);
|
|
||||||
}
|
|
||||||
else if (hasGlassLocationWithMultipleParts) {
|
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, this.$route, {}, {}, result.data);
|
|
||||||
}
|
|
||||||
else if (hasChildPartQuestions) {
|
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS, this.$route, {}, {}, result.data);
|
|
||||||
}
|
|
||||||
else if (hasCapabilityQuestions) {
|
|
||||||
this.$router.navigateWithSaving(this.navigationScenarios.SELECTED_VIN_WITH_CAPABILITY_QUESTIONS, this.$route, {}, {}, result.data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// if single parts only
|
|
||||||
const collectedGlassParts = this.reducedGlassPartsArray(result.data.partsOrQuestions);
|
|
||||||
// save to store lineItems.glassParts
|
|
||||||
this.$store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts);
|
|
||||||
|
|
||||||
// go to heritage quote page
|
|
||||||
this.$refs.loadingModal.showModal();
|
|
||||||
navigateToHeritageFunnel();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,14 +2,11 @@ import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import { setupMocksForJsFiles, getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { setupMocksForJsFiles, getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
|
||||||
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
|
|
||||||
import store from "@/store";
|
|
||||||
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
import loadingModal from '@/common-components/loading-modal/loading-modal.vue';
|
||||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
|
||||||
|
|
||||||
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||||
navigateToHeritageFunnel: jest.fn()
|
navigateForward: jest.fn()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe("vin-pages-mixin", () => {
|
describe("vin-pages-mixin", () => {
|
||||||
|
|
@ -18,955 +15,17 @@ describe("vin-pages-mixin", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("navigateForwardWithSingleCarMatch", () => {
|
describe("navigateForwardWithSingleCarMatch", () => {
|
||||||
describe("should go to parts-questions", () => {
|
test("should navigateForward", async () => {
|
||||||
test("single glass location has part question => go to parts-questions", async () => {
|
// Arrange
|
||||||
// Arrange
|
const { wrapper } = setupMocks({});
|
||||||
const partsOrQuestions = [
|
vehicleQuestionsMixin.methods.navigateForward = jest.fn();
|
||||||
{
|
|
||||||
"glassName": "Single",
|
|
||||||
"glassLocation": "Windshield",
|
|
||||||
"parts": null,
|
|
||||||
"partQuestions": [
|
|
||||||
{
|
|
||||||
"questionSequence": 1,
|
|
||||||
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
|
|
||||||
"answers": [
|
|
||||||
{
|
|
||||||
"answerText": "Yes",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01144"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"answerText": "No",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01143"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
// Act
|
||||||
partsOrQuestions: partsOrQuestions
|
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
// Assert
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
expect(vehicleQuestionsMixin.methods.navigateForward).toHaveBeenCalled();
|
||||||
|
})
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
|
|
||||||
test("multiple glass locations have part questions => go to parts-questions", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Single",
|
|
||||||
"glassLocation": "Windshield",
|
|
||||||
"parts": null,
|
|
||||||
"partQuestions": [
|
|
||||||
{
|
|
||||||
"questionSequence": 1,
|
|
||||||
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
|
|
||||||
"answers": [
|
|
||||||
{
|
|
||||||
"answerText": "Yes",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01144"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"answerText": "No",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01143"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Front",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DD08158GTYN",
|
|
||||||
"description": "driver side, front",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Quarter",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DQ08162GTYN",
|
|
||||||
"description": "driver side, 1 hole",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "SideDoor",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": null,
|
|
||||||
"partQuestions": [
|
|
||||||
{
|
|
||||||
"questionSequence": 2,
|
|
||||||
"questionText": "Is this a super awesome question?",
|
|
||||||
"answers": [
|
|
||||||
{
|
|
||||||
"answerText": "Yes",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01144000"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"answerText": "Super yes",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01143001"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DB08165GTNN",
|
|
||||||
"description": "heated glass, stationary",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
|
|
||||||
test("multiple glass locations selected, one has part question => go to parts-questions", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Single",
|
|
||||||
"glassLocation": "Windshield",
|
|
||||||
"parts": null,
|
|
||||||
"partQuestions": [
|
|
||||||
{
|
|
||||||
"questionSequence": 1,
|
|
||||||
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
|
|
||||||
"answers": [
|
|
||||||
{
|
|
||||||
"answerText": "Yes",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01144"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"answerText": "No",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01143"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Front",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DD08158GTYN",
|
|
||||||
"description": "driver side, front",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Quarter",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DQ08162GTYN",
|
|
||||||
"description": "driver side, 1 hole",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "SideDoor",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DD08160GTYN",
|
|
||||||
"description": "driver side, body side, 1 hole",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DB08165GTNN",
|
|
||||||
"description": "heated glass, stationary",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
|
|
||||||
test("a selected glass location has part questions and multiple parts => go to parts-questions", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Single",
|
|
||||||
"glassLocation": "Windshield",
|
|
||||||
"parts": null,
|
|
||||||
"partQuestions": [
|
|
||||||
{
|
|
||||||
"questionSequence": 1,
|
|
||||||
"questionText": "Is there a line running across the bottom, driver's side then up the center of the Windshield?",
|
|
||||||
"answers": [
|
|
||||||
{
|
|
||||||
"answerText": "Yes",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01144"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"answerText": "No",
|
|
||||||
"nextQuestionSequence": null,
|
|
||||||
"answerResult": "DW01143"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Front",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DD08158GTYN",
|
|
||||||
"description": "driver side, front",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Quarter",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DQ08162GTYN",
|
|
||||||
"description": "driver side, 1 hole",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DQ08162YPYN",
|
|
||||||
"description": "driver side, 1 hole",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "SideDoor",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DD08160GTYN",
|
|
||||||
"description": "driver side, body side, 1 hole",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DD08160YPYN",
|
|
||||||
"description": "driver side, body side, 1 hole",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DB08165GTNN",
|
|
||||||
"description": "heated glass, stationary",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DB08165YPNN",
|
|
||||||
"description": "heated glass, stationary",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DB08166GTNN",
|
|
||||||
"description": "stationary",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DB08167GTNN",
|
|
||||||
"description": "heated glass, movable, 8 hole",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DB08167YPNN",
|
|
||||||
"description": "heated glass, movable, 8 hole",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("should go to vehicle-parts", () => {
|
|
||||||
test("single glass location has multiple parts => go to vehicle-parts", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FB25724GTYN",
|
|
||||||
"description": "heated glass, solar, antenna",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "FB25759GTYN",
|
|
||||||
"description": "heated glass, solar, antenna, w/diversity antenna",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
|
|
||||||
test("multiple glass locations selected, one of them has multiple parts => go to vehicle parts", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Single",
|
|
||||||
"glassLocation": "Windshield",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FW03647GTNN",
|
|
||||||
"description": "solar, 3rd visor band",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": [
|
|
||||||
{
|
|
||||||
"partNumber": "MWF03647",
|
|
||||||
"partType": "MOULDING",
|
|
||||||
"description": "Upper "
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Back",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FD25747GTYN",
|
|
||||||
"description": "solar, driver side, rear, ex models and above",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Front",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FD25719GTYN",
|
|
||||||
"description": "solar, driver side, front, ex models and above",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Vent",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FV25749GTNN",
|
|
||||||
"description": "solar, driver side, rear",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FB25724GTYN",
|
|
||||||
"description": "heated glass, solar, antenna",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "FB25759GTYN",
|
|
||||||
"description": "heated glass, solar, antenna, w/diversity antenna",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
|
|
||||||
test("multiple glass locations selected, multiple have multiple parts => go to vehicle-parts", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Single",
|
|
||||||
"glassLocation": "Windshield",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DW02101GTYN",
|
|
||||||
"description": "solar",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Back",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DD12202GTYN",
|
|
||||||
"description": "solar, driver side, rear",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DD12202YPYN",
|
|
||||||
"description": "solar, driver side, rear",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Front",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DD12198GTYN",
|
|
||||||
"description": "solar, driver side, front",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DD12200GTYN",
|
|
||||||
"description": "solar, driver side, front, laminated, soundproofing",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Quarter",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DQ12204GTYNOEM",
|
|
||||||
"description": "solar, driver side, encap",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DQ12204YPYNOEM",
|
|
||||||
"description": "solar, driver side, encap",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DQ12205GTYNOEM",
|
|
||||||
"description": "solar, antenna, driver side, encap",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DQ12205YPYNOEM",
|
|
||||||
"description": "solar, antenna, driver side, encap",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DQ12207GTYN",
|
|
||||||
"description": "solar, driver side, encap, chrome molding",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DQ12207YPYNOEM",
|
|
||||||
"description": "solar, driver side, encap, chrome molding",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DQ12208GTYNOEM",
|
|
||||||
"description": "solar, antenna, driver side, encap, chrome molding",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DQ12208YPYNOEM",
|
|
||||||
"description": "solar, antenna, driver side, encap, chrome molding",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "DB12209GTYN",
|
|
||||||
"description": "heated glass, solar, 1 hole",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"partNumber": "DB12209YPYN",
|
|
||||||
"description": "heated glass, solar, 1 hole",
|
|
||||||
"color": "Gray Tint Privacy",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("should go to molding-questions", () => {
|
|
||||||
test("single glass location has child part questions => go to molding-questions", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FB25724GTYN",
|
|
||||||
"description": "heated glass, solar, antenna",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null,
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("should go to capability-questions", () => {
|
|
||||||
test("single glass location has no child part questions but requiresCapabilityQuestions is true => go to capability-questions", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FB25724GTYN",
|
|
||||||
"description": "heated glass, solar, antenna",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": true,
|
|
||||||
"childParts": null,
|
|
||||||
"childPartQuestions": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_CAPABILITY_QUESTIONS, wrapper.vm.$route, {}, {}, { partsOrQuestions });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("should go to heritage funnel", () => {
|
|
||||||
test("single glass location selected, has no part questions and has one part => go to heritage funnel", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Single",
|
|
||||||
"glassLocation": "Windshield",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FW04186GTYN",
|
|
||||||
"description": "solar, soundproofing, lane keep assist",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": true,
|
|
||||||
"requiresCapabilityQuestions": false,
|
|
||||||
"childParts": [
|
|
||||||
{
|
|
||||||
"partNumber": "GGG 3563 KIT",
|
|
||||||
"partType": "MOULDING",
|
|
||||||
"description": "Kit, Top & Sides "
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(navigateToHeritageFunnel).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("multiple glass locations selected, each has one part and no part questions => go to heritage funnel", async () => {
|
|
||||||
// Arrange
|
|
||||||
const partsOrQuestions = [
|
|
||||||
{
|
|
||||||
"glassName": "Single",
|
|
||||||
"glassLocation": "Windshield",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FW04186GTYN",
|
|
||||||
"description": "solar, soundproofing, lane keep assist",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": true,
|
|
||||||
"requiresCapabilityQuestions": false,
|
|
||||||
"childParts": [
|
|
||||||
{
|
|
||||||
"partNumber": "GGG 3563 KIT",
|
|
||||||
"partType": "MOULDING",
|
|
||||||
"description": "Kit, Top & Sides "
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Back",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FD25457GTYN",
|
|
||||||
"description": "solar, driver side, rear",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": false,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Front",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FD27090GTYN",
|
|
||||||
"description": "solar, driver side, front",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": false,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Vent",
|
|
||||||
"glassLocation": "Driver",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FV25459GTNN",
|
|
||||||
"description": "solar, driver side, rear",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": false,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"glassName": "Stationary",
|
|
||||||
"glassLocation": "Rear",
|
|
||||||
"parts": [
|
|
||||||
{
|
|
||||||
"partNumber": "FB25460GTYN",
|
|
||||||
"description": "heated glass, solar",
|
|
||||||
"color": "Green Tint",
|
|
||||||
"requiresRecalibration": false,
|
|
||||||
"requiresCapabilityQuestions": false,
|
|
||||||
"childParts": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"partQuestions": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks({
|
|
||||||
partsOrQuestions: partsOrQuestions
|
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.vm.$store.commit = jest.fn();
|
|
||||||
|
|
||||||
const collectedGlassParts = wrapper.vm.reducedGlassPartsArray(partsOrQuestions);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.navigateForwardWithSingleCarMatch();
|
|
||||||
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.$store.commit).toHaveBeenCalledTimes(1);
|
|
||||||
expect(wrapper.vm.$store.commit).toHaveBeenCalledWith(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts)
|
|
||||||
expect(wrapper.vm.$refs.loadingModal.showModal).toHaveBeenCalledTimes(1);
|
|
||||||
expect(navigateToHeritageFunnel).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
|
||||||
// Heritage integration
|
// Heritage integration
|
||||||
import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper";
|
import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper";
|
||||||
import { updateOrCreateFunnelCookie, getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
import { updateOrCreateFunnelCookie, getFunnelCookie, updateSessionIdCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
import { loadOrderIfPresent, saveOrder } from "@/helpers/heritage-integration/order-helper";
|
import { loadOrderIfPresent, saveOrder } from "@/helpers/heritage-integration/order-helper";
|
||||||
import { getPageToRouteExistingOrderTo, navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import { getPageToRouteExistingOrderTo, navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
||||||
|
|
@ -31,6 +31,9 @@ const routes = [
|
||||||
if (analyticsMixin.methods.noSession()) {
|
if (analyticsMixin.methods.noSession()) {
|
||||||
await analyticsMixin.methods.initSession();
|
await analyticsMixin.methods.initSession();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
updateSessionIdCookie();
|
||||||
|
}
|
||||||
|
|
||||||
if (getFunnelCookie()?.SuppressConceptFunnel) {
|
if (getFunnelCookie()?.SuppressConceptFunnel) {
|
||||||
await navigateToHeritageFunnel(false);
|
await navigateToHeritageFunnel(false);
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,34 @@
|
||||||
const navigationScenarios = {
|
const navigationScenarios = {
|
||||||
|
// General
|
||||||
|
CLICKED_BACK: "CLICKED_BACK",
|
||||||
|
CLICKED_FORWARD: "CLICKED_FORWARD",
|
||||||
|
|
||||||
|
// YMMS
|
||||||
SELECTED_YEAR: "SELECTED_YEAR",
|
SELECTED_YEAR: "SELECTED_YEAR",
|
||||||
SELECTED_MODEL: "SELECTED_MODEL",
|
SELECTED_MODEL: "SELECTED_MODEL",
|
||||||
SELECTED_MAKE: "SELECTED_MAKE",
|
SELECTED_MAKE: "SELECTED_MAKE",
|
||||||
SELECTED_STYLE: "SELECTED_STYLE",
|
SELECTED_STYLE: "SELECTED_STYLE",
|
||||||
CLICKED_BACK: "CLICKED_BACK",
|
|
||||||
|
// Vin pages
|
||||||
CLICKED_BACK_WITH_VIN: "CLICKED_BACK_WITH_VIN",
|
CLICKED_BACK_WITH_VIN: "CLICKED_BACK_WITH_VIN",
|
||||||
CLICKED_FORWARD: "CLICKED_FORWARD",
|
|
||||||
CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN",
|
CLICKED_FORWARD_WITH_VIN: "CLICKED_FORWARD_WITH_VIN",
|
||||||
SELECTED_PARTS: "SELECTED_PARTS",
|
CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN",
|
||||||
SELECTED_VIN_WITH_PART_QUESTIONS: "SELECTED_VIN_WITH_PART_QUESTIONS",
|
|
||||||
SELECTED_VIN_WITH_MULTIPLE_PARTS: "SELECTED_VIN_WITH_MULTIPLE_PARTS",
|
|
||||||
SELECTED_VIN_WITH_MOLDING_QUESTIONS: "SELECTED_VIN_WITH_MOLDING_QUESTIONS",
|
|
||||||
SELECTED_VIN_WITH_CAPABILITY_QUESTIONS: "SELECTED_VIN_WITH_CAPABILITY_QUESTIONS",
|
|
||||||
CONTINUING_WITH_SINGLE_PART: "CONTINUING_WITH_SINGLE_PART",
|
|
||||||
CONTINUING_WITH_MULTIPLE_VEHICLES: "CONTINUING_WITH_MULTIPLE_VEHICLES",
|
CONTINUING_WITH_MULTIPLE_VEHICLES: "CONTINUING_WITH_MULTIPLE_VEHICLES",
|
||||||
SELECTED_VIN_HAS_MISMATCHED_GLASS: "SELECTED_VIN_HAS_MISMATCHED_GLASS",
|
SELECTED_VIN_HAS_MISMATCHED_GLASS: "SELECTED_VIN_HAS_MISMATCHED_GLASS",
|
||||||
CLICKED_FORWARD_WITHOUT_VIN: "CLICKED_FORWARD_WITHOUT_VIN",
|
|
||||||
SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN",
|
SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN",
|
||||||
SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE",
|
SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE",
|
||||||
SELECTED_HOME_ADDRESS: "SELECTED_HOME_ADDRESS",
|
SELECTED_HOME_ADDRESS: "SELECTED_HOME_ADDRESS",
|
||||||
ANSWERED_QUESTIONS_WITH_SINGLE_PART: "ANSWERED_QUESTIONS_WITH_SINGLE_PART",
|
|
||||||
ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS: "ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS",
|
// Question pages
|
||||||
SELECTED_PROVIDE_VIN_DIFFERENT_WAY: "SELECTED_PROVIDE_VIN_DIFFERENT_WAY",
|
HAS_PART_QUESTIONS: "HAS_PART_QUESTIONS",
|
||||||
CLICKED_BACK_WITH_PART_QUESTION_ANSWERS: "CLICKED_BACK_WITH_PART_QUESTION_ANSWERS",
|
HAS_MULTIPLE_PARTS_TO_CHOOSE: "HAS_MULTIPLE_PARTS_TO_CHOOSE",
|
||||||
CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS: "CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS",
|
|
||||||
HAS_MOLDING_QUESTIONS: "HAS_MOLDING_QUESTIONS",
|
HAS_MOLDING_QUESTIONS: "HAS_MOLDING_QUESTIONS",
|
||||||
HAS_CAPABILITY_QUESTIONS: "HAS_CAPABILITY_QUESTIONS",
|
HAS_CAPABILITY_QUESTIONS: "HAS_CAPABILITY_QUESTIONS",
|
||||||
|
HAS_NO_MORE_QUESTIONS: "HAS_NO_MORE_QUESTIONS",
|
||||||
|
CLICKED_BACK_TO_GO_TO_VIN_LOOKUP: "CLICKED_BACK_TO_GO_TO_VIN_LOOKUP",
|
||||||
|
CLICKED_BACK_TO_GO_TO_PART_QUESTIONS: "CLICKED_BACK_TO_GO_TO_PART_QUESTIONS",
|
||||||
|
CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS: "CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS",
|
||||||
|
CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS: "CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS"
|
||||||
};
|
};
|
||||||
|
|
||||||
export { navigationScenarios };
|
export { navigationScenarios };
|
||||||
|
|
|
||||||
|
|
@ -69,27 +69,6 @@ const routingTable = function(store) {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
fmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
|
||||||
maps: [
|
|
||||||
{
|
|
||||||
scenario: navigationScenarios.SELECTED_PARTS,
|
|
||||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
|
||||||
destinationFmgPageValue: fmgPageValues.REVEAL,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_BACK_WITH_PART_QUESTION_ANSWERS,
|
|
||||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scenario: navigationScenarios.CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS,
|
|
||||||
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
fmgPageValue: fmgPageValues.REVEAL,
|
fmgPageValue: fmgPageValues.REVEAL,
|
||||||
maps: [
|
maps: [
|
||||||
|
|
@ -97,10 +76,6 @@ const routingTable = function(store) {
|
||||||
scenario: navigationScenarios.CLICKED_BACK,
|
scenario: navigationScenarios.CLICKED_BACK,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
scenario: navigationScenarios.SELECTED_PARTS,
|
|
||||||
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -119,19 +94,19 @@ const routingTable = function(store) {
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
|
scenario: navigationScenarios.HAS_PART_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
|
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS,
|
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_CAPABILITY_QUESTIONS,
|
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -148,19 +123,19 @@ const routingTable = function(store) {
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
|
scenario: navigationScenarios.HAS_PART_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
|
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS,
|
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_CAPABILITY_QUESTIONS,
|
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -181,19 +156,19 @@ const routingTable = function(store) {
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
|
scenario: navigationScenarios.HAS_PART_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
|
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS,
|
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_CAPABILITY_QUESTIONS,
|
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -210,25 +185,21 @@ const routingTable = function(store) {
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS,
|
scenario: navigationScenarios.HAS_PART_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS,
|
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS,
|
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.SELECTED_VIN_WITH_CAPABILITY_QUESTIONS,
|
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS
|
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS
|
||||||
},
|
},
|
||||||
{
|
|
||||||
scenario: navigationScenarios.SELECTED_PROVIDE_VIN_DIFFERENT_WAY,
|
|
||||||
destinationFmgPageValue: fmgPageValues.ESTIMATE
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -256,11 +227,11 @@ const routingTable = function(store) {
|
||||||
fmgPageValue: fmgPageValues.PART_QUESTIONS,
|
fmgPageValue: fmgPageValues.PART_QUESTIONS,
|
||||||
maps: [
|
maps: [
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_BACK,
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP,
|
||||||
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
|
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS,
|
scenario: navigationScenarios.HAS_MULTIPLE_PARTS_TO_CHOOSE,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -272,31 +243,88 @@ const routingTable = function(store) {
|
||||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.ANSWERED_QUESTIONS_WITH_SINGLE_PART,
|
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fmgPageValue: fmgPageValues.VEHICLE_PARTS,
|
||||||
|
maps: [
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_FORWARD,
|
||||||
|
destinationFmgPageValue: fmgPageValues.REVEAL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.HAS_MOLDING_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
fmgPageValue: fmgPageValues.MOLDING_QUESTIONS,
|
||||||
maps: [
|
maps: [
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_BACK,
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
scenario: navigationScenarios.HAS_CAPABILITY_QUESTIONS,
|
||||||
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
destinationFmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
fmgPageValue: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
maps: [
|
maps: [
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_BACK,
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VIN_LOOKUP,
|
||||||
|
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_PART_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.PART_QUESTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_VEHICLE_PARTS,
|
||||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_BACK_TO_GO_TO_MOLDING_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.HAS_NO_MORE_QUESTIONS,
|
||||||
|
destinationFmgPageValue: fmgPageValues.QUOTE
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ const getDefaultState = () => {
|
||||||
numberOfChips: null,
|
numberOfChips: null,
|
||||||
glassToReplace: null,
|
glassToReplace: null,
|
||||||
partQuestionAnswers: null,
|
partQuestionAnswers: null,
|
||||||
|
capabilityQuestionAnswers: null
|
||||||
},
|
},
|
||||||
lineItems: {
|
lineItems: {
|
||||||
glassParts: null
|
glassParts: null
|
||||||
|
|
@ -126,6 +127,9 @@ export const mutations = {
|
||||||
updatePartQuestionAnswers(state, answersArray) {
|
updatePartQuestionAnswers(state, answersArray) {
|
||||||
state.order.damage.partQuestionAnswers = answersArray;
|
state.order.damage.partQuestionAnswers = answersArray;
|
||||||
},
|
},
|
||||||
|
updateCapabilityQuestionAnswers(state, answersArray) {
|
||||||
|
state.order.damage.capabilityQuestionAnswers = answersArray;
|
||||||
|
},
|
||||||
updateGlassParts(state, partsData) {
|
updateGlassParts(state, partsData) {
|
||||||
state.order.lineItems.glassParts = partsData;
|
state.order.lineItems.glassParts = partsData;
|
||||||
},
|
},
|
||||||
|
|
@ -277,6 +281,7 @@ export const mutations = {
|
||||||
resetGlassPartsState(state) {
|
resetGlassPartsState(state) {
|
||||||
state.order.lineItems.glassParts = null;
|
state.order.lineItems.glassParts = null;
|
||||||
state.order.damage.partQuestionAnswers = null;
|
state.order.damage.partQuestionAnswers = null;
|
||||||
|
state.order.damage.capabilityQuestionAnswers = null;
|
||||||
state.applicationUser.pageData[fmgPageValues.PART_QUESTIONS] = null;
|
state.applicationUser.pageData[fmgPageValues.PART_QUESTIONS] = null;
|
||||||
state.applicationUser.pageData[fmgPageValues.VEHICLE_PARTS] = null;
|
state.applicationUser.pageData[fmgPageValues.VEHICLE_PARTS] = null;
|
||||||
state.applicationUser.pageData[fmgPageValues.MOLDING_QUESTIONS] = null;
|
state.applicationUser.pageData[fmgPageValues.MOLDING_QUESTIONS] = null;
|
||||||
|
|
@ -737,6 +742,29 @@ export const actions = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCapabilityQuestions(context, { carId, partNumber }) {
|
||||||
|
return globalMethods.callHttpClient({
|
||||||
|
method: endpoints.GetCapabilityQuestions.method,
|
||||||
|
endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getPartFromCapabilityQuestionAnswer(context, selectedAnswerResult1) {
|
||||||
|
const pageData = context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS);
|
||||||
|
|
||||||
|
const part = pageData.partsOrQuestions.find(x => x.glassLocation === damageLocationsSelected.WINDSHIELD).parts[0];
|
||||||
|
const capabilityQuestionAnswers = context.getters.damage.capabilityQuestionAnswers;
|
||||||
|
|
||||||
|
return globalMethods.callHttpClient({
|
||||||
|
method: endpoints.ApplyCapabilityAnswerToPart.method,
|
||||||
|
endpoint: endpoints.ApplyCapabilityAnswerToPart.url,
|
||||||
|
payload: {
|
||||||
|
part,
|
||||||
|
capabilityAnswerResults: capabilityQuestionAnswers
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
// Order API Actions
|
// Order API Actions
|
||||||
saveOrder(context) {
|
saveOrder(context) {
|
||||||
const vehicle = context.getters.vehicle;
|
const vehicle = context.getters.vehicle;
|
||||||
|
|
@ -967,10 +995,22 @@ export const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
||||||
|
// if part question answers have changed, reset subsequent question answers
|
||||||
|
const previousResultsArray = context.getters.damage.partQuestionAnswers;
|
||||||
|
const havePartQuestionAnswersChanged = previousResultsArray?.length !== partQuestionAnswersArray.length ||
|
||||||
|
!previousResultsArray.every((x, i) => x.result === partQuestionAnswersArray[i].result);
|
||||||
|
|
||||||
|
if (havePartQuestionAnswersChanged) {
|
||||||
|
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||||
|
}
|
||||||
|
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
|
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
|
||||||
},
|
},
|
||||||
|
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
|
||||||
|
//Save new values
|
||||||
|
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, capabilityQuestionAnswers);
|
||||||
|
},
|
||||||
// Misc order actions
|
// Misc order actions
|
||||||
saveServiceLocation(context, serviceLocationInfo) {
|
saveServiceLocation(context, serviceLocationInfo) {
|
||||||
context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo);
|
context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo);
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ describe("list-button.vue", () => {
|
||||||
wrapper.vm.handleCheckChange();
|
wrapper.vm.handleCheckChange();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.emitted()["isCheckedChanged"][0]).toEqual([{value: "List Card Checkbox", checkValue: Boolean, buttonId: 'list-card-id'}]);
|
expect(wrapper.emitted()["isCheckedChanged"][0]).toEqual([{value: "List Card Checkbox", checkValue: false, buttonId: 'list-card-id'}]);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -204,11 +204,11 @@ describe("list-button.vue", () => {
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
isWide: false,
|
isWide: false,
|
||||||
modelValue: ["List Card Checkbox"],
|
modelValue: ["List Card Checkbox"],
|
||||||
selectedValues: ["Car-Front"]
|
selectedValues: "Car-Front"
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.componentVM.checkValue).toEqual("Car-Front");
|
expect(wrapper.componentVM.checkValue).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleInputChange is triggered", async () => {
|
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleInputChange is triggered", async () => {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
:value="value"
|
:value="value"
|
||||||
:aria-required="isRequired"
|
:aria-required="isRequired"
|
||||||
v-model="checkValue"
|
v-model="checkValue"
|
||||||
|
:checked="checkValue"
|
||||||
@change="handleInputChange"
|
@change="handleInputChange"
|
||||||
:aria-label="value"
|
:aria-label="value"
|
||||||
>
|
>
|
||||||
|
|
@ -54,6 +55,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useField } from "vee-validate";
|
import { useField } from "vee-validate";
|
||||||
|
import { toRef } from "vue";
|
||||||
import loader from "@/ux-components/loader/loader";
|
import loader from "@/ux-components/loader/loader";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
|
||||||
|
|
@ -85,17 +87,28 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoaderDisplayed: false,
|
isLoaderDisplayed: false,
|
||||||
checkValue: Boolean,
|
checkValue: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
mounted() {
|
||||||
if (Array.isArray(this.selectedValues)) {
|
if (Array.isArray(this.validateValue)) {
|
||||||
this.checkValue = this.isMultiSelect
|
this.checkValue = this.isValueSelectedByArray(this.selectedValues);
|
||||||
? this.selectedValues.includes(this.value)
|
const isSelectedByValidator = this.isValueSelectedByArray(this.validateValue);
|
||||||
: this.selectedValues[0];
|
|
||||||
|
if (this.checkValue != isSelectedByValidator) {
|
||||||
|
this.handleChange(this.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.checkValue = this.selectedValues == this.value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
isValueSelectedByArray(arr) {
|
||||||
|
return this.isMultiSelect
|
||||||
|
? arr.includes(this.value)
|
||||||
|
: arr[0];
|
||||||
|
},
|
||||||
displayLoader() {
|
displayLoader() {
|
||||||
this.isLoaderDisplayed = true;
|
this.isLoaderDisplayed = true;
|
||||||
},
|
},
|
||||||
|
|
@ -148,11 +161,14 @@ export default {
|
||||||
const {
|
const {
|
||||||
handleChange,
|
handleChange,
|
||||||
errors,
|
errors,
|
||||||
} = useField(props.groupName, props.validationRules, fieldOptions);
|
value
|
||||||
|
} = useField(toRef(props, "groupName"), toRef(props, "validationRules"), fieldOptions);
|
||||||
|
|
||||||
|
const validateValue = value;
|
||||||
return {
|
return {
|
||||||
handleChange,
|
handleChange,
|
||||||
errors,
|
errors,
|
||||||
|
validateValue,
|
||||||
fieldOptions, // only need to expose this for unit test purposes
|
fieldOptions, // only need to expose this for unit test purposes
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue