CSR-612 Fix merge conflict
This commit is contained in:
commit
2f7ca13640
10 changed files with 247 additions and 42 deletions
|
|
@ -2,7 +2,7 @@
|
|||
<template>
|
||||
<div :class="isOverflowScrollable ? 'button-question button-question-overflow' : 'button-question'">
|
||||
<div v-if="questionText && answers && answers.length > 0" class="question-text d-flex">
|
||||
<span class="fs-5 fw-bold w-100">{{ questionText }}</span>
|
||||
<span class="fw-bold w-100">{{ questionText }}</span>
|
||||
</div>
|
||||
<div class="w-100 d-flex justify-content-center">
|
||||
<fieldset class="w-100" :aria-required=isRequired :class="getFieldSetClasses" :role="isMultiSelect ? 'group' : 'radiogroup'" :aria-labelledby="formattedGroupName">
|
||||
|
|
@ -214,6 +214,8 @@ export default {
|
|||
.question-text {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.625rem;
|
||||
|
||||
& > span {
|
||||
text-align: center;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
:questionText="q.questionText"
|
||||
:answers="q.answers"
|
||||
:groupName="`${questionData.glassName}-${questionData.glassLocation}-${i}`"
|
||||
v-model="selectedValuesArray"
|
||||
v-model="selectedValue"
|
||||
isRequired
|
||||
:validationRules="validationRules"
|
||||
:clearOnUnmount=false
|
||||
|
|
@ -25,13 +25,14 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
currentQuestionNum: 1,
|
||||
questions: [{ "BlankObject": "NOT USED... placeholder for question #0"}],
|
||||
questions: [{ "BlankObject": "NOT USED... placeholder for question #0 to simplify indexing"}],
|
||||
};
|
||||
},
|
||||
props: {
|
||||
questionData: Object,
|
||||
validationRules: String,
|
||||
modelValue: Array,
|
||||
partIndex: Number,
|
||||
},
|
||||
created() {
|
||||
this.questionData.partQuestions.map((q, i) => {
|
||||
|
|
@ -61,12 +62,11 @@ export default {
|
|||
});
|
||||
},
|
||||
computed: {
|
||||
selectedValuesArray: {
|
||||
selectedValue: {
|
||||
get: function() {
|
||||
return [];
|
||||
return "";
|
||||
},
|
||||
set: function(returnedAnswerArray) {
|
||||
const returnedAnswer = returnedAnswerArray[returnedAnswerArray.length-1];
|
||||
set: function(returnedAnswer) {
|
||||
const isQuestionChainComplete = this.handleReturnedAnswer(returnedAnswer);
|
||||
|
||||
if (isQuestionChainComplete) {
|
||||
|
|
@ -102,6 +102,7 @@ export default {
|
|||
|
||||
// set this question as "answered"
|
||||
this.questions[questionNum].answerSelected = questionAnswerText;
|
||||
this.questions[questionNum].answerNumber = questionNum;
|
||||
|
||||
// update to next question index
|
||||
this.currentQuestionNum = questionType === "nextQuestion" ? parseInt(questionAnswer) : parseInt(questionNum); // update count to display next question
|
||||
|
|
@ -116,16 +117,17 @@ export default {
|
|||
answeredQuestions.push({
|
||||
questionText: q.questionText,
|
||||
selectedAnswerText: q.answerSelected,
|
||||
questionNum: questionNum,
|
||||
questionNum: q.answerNumber,
|
||||
});
|
||||
}
|
||||
});
|
||||
return {
|
||||
answerResult: questionAnswer,
|
||||
answeredQuestions: answeredQuestions,
|
||||
partIndex: this.partIndex,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
currentQuestion: {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ const endpoints = {
|
|||
url: "/parts/api/v1/parts/parts-or-questions",
|
||||
method: "POST",
|
||||
},
|
||||
GetParts: {
|
||||
url: "/parts/api/v1/parts/parts",
|
||||
method: "POST",
|
||||
},
|
||||
SaveOrder: {
|
||||
url: "/order/api/v1/order/save",
|
||||
method: "POST",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ const storeActions = {
|
|||
LOOKUP_VIN_BY_ADDRESS: "lookupVinByAddress",
|
||||
|
||||
GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions",
|
||||
GET_PARTS: "getParts",
|
||||
SAVE_ORDER: "saveOrder",
|
||||
LOAD_ORDER: "loadOrder",
|
||||
SET_REFERRAL_INFORMATION: "setReferralInformation",
|
||||
|
|
@ -31,7 +32,6 @@ const storeActions = {
|
|||
GET_EXPERIMENTS_BY_USER: "GetExperimentsByUser",
|
||||
CLEAR_VIN: "clearVin",
|
||||
|
||||
|
||||
// DEPENDENCY MUTATIONS
|
||||
RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies",
|
||||
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
|
||||
|
|
@ -51,7 +51,8 @@ const storeActions = {
|
|||
SAVE_REGISTRATION_LICENSE_PLATE_LOOKUP: "saveRegistrationLicensePlateLookup",
|
||||
SAVE_VIN: "saveVin",
|
||||
SAVE_REGISTRATION_ADDRESS_LOOKUP: "saveRegistrationAddressLookup",
|
||||
SAVE_GLASS_PARTS: "saveGlassParts",
|
||||
SAVE_GLASS_PARTS: "saveGlassParts",
|
||||
SAVE_PART_QUESTION_ANSWERS: "savePartQuestionAnswers",
|
||||
};
|
||||
|
||||
export { storeActions };
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const storeMutations = {
|
|||
UPDATE_IS_REPAIR: "updateIsRepair",
|
||||
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
|
||||
UPDATE_GLASS_TO_REPLACE: "updateGlassToReplace",
|
||||
UPDATE_PART_QUESTION_ANSWERS: "updatePartQuestionAnswers",
|
||||
UPDATE_GLASS_PARTS: "updateGlassParts",
|
||||
|
||||
UPDATE_REGISTRATION_LICENSE_PLATE : "updateRegistrationLicensePlate",
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@
|
|||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||
<alert
|
||||
ref="alertFoundMultipleVehicles"
|
||||
class="my-5"
|
||||
alertClass="alert-warning"
|
||||
:manualHeadline="AlertFoundMultipleVehiclesHeader"
|
||||
class="my-5"
|
||||
alertClass="alert-warning"
|
||||
:manualHeadline="AlertFoundMultipleVehiclesHeader"
|
||||
manualCopy=""
|
||||
v-bind:isDismissible="false"
|
||||
/>
|
||||
v-bind:isDismissible="false"
|
||||
/>
|
||||
<addressVehiclesQuestion
|
||||
ref="addressVehiclesQuestion"
|
||||
cmsWidgetName="VehicleConfirmationQuestion"
|
||||
|
|
|
|||
|
|
@ -1,33 +1,67 @@
|
|||
<template>
|
||||
<div class="page-container-grouped-styles">
|
||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
||||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage=false />
|
||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||
<div class="fade-on-route-transition sub-container make-tall">
|
||||
<h1>Part Questions Page Placeholder</h1>
|
||||
<funnel-footer cmsWidgetName="FunnelFooterWidget" @back-clicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
<Form
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit"
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
>
|
||||
<div class="page-container-grouped-styles part-questions">
|
||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
||||
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage=false />
|
||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||
<div class="fade-on-route-transition sub-container make-tall">
|
||||
<alert
|
||||
ref="alertFewMoreQuestions"
|
||||
class="my-5"
|
||||
alertClass="alert-warning"
|
||||
:manualHeadline="AlertFewMoreQuestionsHeader"
|
||||
:manualCopy="AlertFewMoreQuestionsCopy"
|
||||
v-bind:isDismissible="false"
|
||||
/>
|
||||
<div v-for="(part, i) in partsQuestionsData" :key="i">
|
||||
<questionChain
|
||||
ref="questionChain"
|
||||
v-model="selectedModel"
|
||||
:questionData="part"
|
||||
:partIndex="i"
|
||||
v-if="showThisPartQuestionChain(part, i)"
|
||||
validationRules="questions-required"
|
||||
/>
|
||||
</div>
|
||||
<funnel-footer
|
||||
ref="funnelFooter"
|
||||
cmsWidgetName="FunnelFooterWidget"
|
||||
:isForwardActionDisabled="waitingForLoad || !meta.valid"
|
||||
@back-clicked="backButtonAction"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Components
|
||||
import funnelHeader from "@/common-components/funnel-header/funnel-header";
|
||||
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
import questionChain from "@/common-components/question-chain/question-chain";
|
||||
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
|
||||
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
|
||||
|
||||
// Supporting Files
|
||||
import {
|
||||
fetchCmsContentForPage
|
||||
} from "@/helpers/cms-content-helper";
|
||||
import {
|
||||
settleAllPromises
|
||||
} from "@/helpers/layout-helper";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import store from "@/store";
|
||||
import {
|
||||
fmgPageValues
|
||||
} from "@/router/router-constants/fmgPage-values";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("questions-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
||||
export default {
|
||||
name: "part-questions",
|
||||
|
|
@ -36,10 +70,12 @@ export default {
|
|||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [{
|
||||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
}, ];
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
},
|
||||
];
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
|
|
@ -48,7 +84,46 @@ export default {
|
|||
vm.setCmsContent(resultMap.cmsContent);
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedModel: [],
|
||||
partsQuestionsData: [],
|
||||
waitingForLoad: true,
|
||||
currentPartNum: 0,
|
||||
glassNameAndParts: [],
|
||||
hasMultipleParts: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
AlertFewMoreQuestionsHeader() {
|
||||
return this.getCmsContent("AlertPartsQuestions", "HeadlineText");
|
||||
},
|
||||
AlertFewMoreQuestionsCopy() {
|
||||
return this.getCmsContent("AlertPartsQuestions", "BodyText");
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
const questionData = await this.$store.getters.pageData(fmgPageValues.PART_QUESTIONS);
|
||||
|
||||
// Map API result data, to part-questions data structure
|
||||
this.partsQuestionsData = questionData.partsOrQuestions.filter((p) => {
|
||||
if (Array.isArray(p.partQuestions) && p.partQuestions.length > 0) {
|
||||
return {
|
||||
glassName: p.glassName,
|
||||
glassLocation: p.glassLocation,
|
||||
partQuestions: p.partQuestions,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
this.waitingForLoad = false;
|
||||
},
|
||||
methods: {
|
||||
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.navigate(
|
||||
|
|
@ -56,16 +131,93 @@ export default {
|
|||
this.$route
|
||||
);
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
const partQuestionAnswersArray = this.partsQuestionsData.map((item) => {
|
||||
return {
|
||||
glassLocation: item.glassLocation,
|
||||
glassName: item.glassName,
|
||||
result: item.answerData.answerResult,
|
||||
answeredQuestions: item.answerData.answeredQuestions,
|
||||
};
|
||||
});
|
||||
|
||||
// save to vuex store as order.damage.partQuestionAnswers (array)
|
||||
await this.dispatchStoreAction(this.storeActions.SAVE_PART_QUESTION_ANSWERS, partQuestionAnswersArray, false);
|
||||
|
||||
// call API parts method
|
||||
const partsLookup = await this.dispatchStoreAction(storeActions.GET_PARTS)
|
||||
.catch(() => {
|
||||
this.$refs.funnelFooter.removeLoader();
|
||||
});
|
||||
|
||||
if (!partsLookup) { return }
|
||||
|
||||
this.glassNameAndParts = partsLookup.data.glassNameAndParts;
|
||||
|
||||
// test response data for multiple parts
|
||||
this.hasMultipleParts = this.glassNameAndParts.some((glass) => glass.parts?.length > 1);
|
||||
|
||||
// loop through all glass items
|
||||
const collectedGlassParts = [];
|
||||
this.glassNameAndParts.forEach((glass) => {
|
||||
if (Array.isArray(glass.parts) && glass.parts.length === 1) {
|
||||
const singlePart = glass.parts[0];
|
||||
collectedGlassParts.push({
|
||||
"partNumber": singlePart.partNumber,
|
||||
"description": singlePart.description,
|
||||
"color": singlePart.color,
|
||||
"requiresRecalibration": singlePart.requiresRecalibration,
|
||||
"childParts": singlePart.childParts,
|
||||
"price": singlePart.price,
|
||||
})
|
||||
}
|
||||
});
|
||||
store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts);
|
||||
this.navigateForward();
|
||||
},
|
||||
async navigateForward() {
|
||||
if (this.hasMultipleParts) {
|
||||
// if multiple parts on any glass
|
||||
// go to vehicle-parts page and pass the partsData
|
||||
this.$router.navigate(this.navigationScenarios.ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS,this.$route,{},{},{partsOrQuestions: this.glassNameAndParts});
|
||||
} else {
|
||||
// if single parts only
|
||||
// go to quote page
|
||||
this.$router.navigate(this.navigationScenarios.ANSWERED_QUESTIONS_WITH_SINGLE_PART,this.$route);
|
||||
}
|
||||
},
|
||||
arePagePrerequisitesValid() {
|
||||
return Object.keys(store.getters.pageData(fmgPageValues.PART_QUESTIONS)).length !== 0;
|
||||
return Object.keys(store.getters.pageData(fmgPageValues.PART_QUESTIONS)).length > 0;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectedModel(model) {
|
||||
this.partsQuestionsData[model.partIndex].answerData = {
|
||||
answerResult: model.answerResult,
|
||||
answeredQuestions: model.answeredQuestions,
|
||||
}
|
||||
this.currentPartNum = model.partIndex + 1;
|
||||
},
|
||||
},
|
||||
data() {},
|
||||
components: {
|
||||
funnelHeader,
|
||||
vehicleBanner,
|
||||
alert,
|
||||
questionChain,
|
||||
funnelSubHeader,
|
||||
funnelFooter,
|
||||
Form,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.part-questions {
|
||||
.question-text {
|
||||
margin-bottom: .5rem;
|
||||
span {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ const navigationScenarios = {
|
|||
SELECTED_MANUAL_VIN: "SELECTED_MANUAL_VIN",
|
||||
SELECTED_LICENSE_PLATE: "SELECTED_LICENSE_PLATE",
|
||||
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",
|
||||
};
|
||||
|
||||
export { navigationScenarios };
|
||||
|
|
|
|||
|
|
@ -216,7 +216,15 @@ const routingTable = [
|
|||
{
|
||||
scenario: navigationScenarios.CLICKED_BACK,
|
||||
destinationFmgPageValue: fmgPageValues.VIN_LOOKUP
|
||||
}
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS,
|
||||
destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS
|
||||
},
|
||||
{
|
||||
scenario: navigationScenarios.ANSWERED_QUESTIONS_WITH_SINGLE_PART,
|
||||
destinationFmgPageValue: fmgPageValues.QUOTE,
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ const getDefaultState = () => {
|
|||
isRepair: null,
|
||||
numberOfChips: null,
|
||||
glassToReplace: null,
|
||||
partQuestionAnswers: null,
|
||||
},
|
||||
lineItems: {
|
||||
glassParts: null,
|
||||
|
|
@ -112,6 +113,9 @@ export const mutations = {
|
|||
updateGlassToReplace(state, glassToReplace) {
|
||||
state.order.damage.glassToReplace = glassToReplace;
|
||||
},
|
||||
updatePartQuestionAnswers(state, answersArray) {
|
||||
state.order.damage.partQuestionAnswers = answersArray;
|
||||
},
|
||||
updateGlassParts(state, partsData) {
|
||||
state.order.lineItems.glassParts = partsData;
|
||||
},
|
||||
|
|
@ -555,7 +559,7 @@ export const actions = {
|
|||
});
|
||||
},
|
||||
|
||||
// Parts API Actions
|
||||
// PartsOrQuestions API Actions
|
||||
getPartsOrQuestions(context) {
|
||||
const vehicle = context.getters.vehicle;
|
||||
const damage = context.getters.damage;
|
||||
|
|
@ -578,6 +582,31 @@ export const actions = {
|
|||
});
|
||||
},
|
||||
|
||||
// Parts API Actions
|
||||
getParts(context) {
|
||||
const vehicle = context.getters.vehicle;
|
||||
const damage = context.getters.damage;
|
||||
const order = context.state.order;
|
||||
|
||||
const carId = vehicle.carId;
|
||||
const glassArray = damage.glassToReplace;
|
||||
const resultsArray = damage.partQuestionAnswers;
|
||||
const zipCode = order.serviceLocation.zipCode;
|
||||
const vin = vehicle.vin;
|
||||
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetParts.method,
|
||||
endpoint: endpoints.GetParts.url,
|
||||
payload: {
|
||||
carId: carId,
|
||||
glass: glassArray,
|
||||
answerResults: resultsArray,
|
||||
zip: zipCode,
|
||||
vin: vin
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// Order API Actions
|
||||
saveOrder(context) {
|
||||
const vehicle = context.getters.vehicle;
|
||||
|
|
@ -787,6 +816,10 @@ export const actions = {
|
|||
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
||||
}
|
||||
},
|
||||
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
||||
//Save new values
|
||||
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
|
||||
},
|
||||
|
||||
// Misc order actions
|
||||
saveServiceLocation(context, serviceLocationInfo) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue