binding
This commit is contained in:
parent
d9dc1eeb7e
commit
32a7cd077d
7 changed files with 172 additions and 69 deletions
|
|
@ -22,8 +22,8 @@
|
|||
:selectingInitiatesLoad="selectingInitiatesLoad"
|
||||
:loaderColor="loaderColor"
|
||||
:loaderPosition="loaderPosition"
|
||||
:isWide="isWide"
|
||||
:isRequired="isRequired"
|
||||
:isWide=isWide
|
||||
:isRequired=isRequired
|
||||
:buttonImage="answer.AnswerImageUrl"
|
||||
:buttonImageId="answer.ImageId"
|
||||
:altText="answer.Name ? answer.Name : answer"
|
||||
|
|
|
|||
|
|
@ -4,45 +4,54 @@
|
|||
|
||||
const customMappings = {
|
||||
glassname: [
|
||||
{ key: 'Single Windshield', transformedValue: 'windshield' },
|
||||
{ key: 'Driver split windshield', transformedValue: 'driver side split windshield' },
|
||||
{ key: 'Passenger split windshield', transformedValue: 'passenger side split windshield' },
|
||||
{ key: 'Stationary backglass', transformedValue: 'rear window' },
|
||||
{ key: 'Sliding backglass', transformedValue: 'rear window' },
|
||||
{ key: 'Driver front door', transformedValue: 'driver side front door' },
|
||||
{ key: 'Driver back door ', transformedValue: 'driver side back door' },
|
||||
{ key: 'Driver vent', transformedValue: 'driver side vent glass' },
|
||||
{ key: 'Driver quarter', transformedValue: 'driver side quarter panel' },
|
||||
{ key: 'Driver sliding door', transformedValue: 'driver side sliding door' },
|
||||
{ key: 'Passenger front door', transformedValue: 'passenger side front door' },
|
||||
{ key: 'Passenger back door', transformedValue: 'passenger side back door' },
|
||||
{ key: 'Passenger vent', transformedValue: 'passenger side vent glass' },
|
||||
{ key: 'Passenger quarter', transformedValue: 'passenger side quarter panel' },
|
||||
{ key: 'Passenger sliding door', transformedValue: 'passenger side sliding door' },
|
||||
{ key: 'Windshield Single', transformedValue: 'windshield' },
|
||||
{ key: 'Windshield Driver', transformedValue: 'driver side split windshield' },
|
||||
{ key: 'Windshield Passenger', transformedValue: 'passenger side split windshield' },
|
||||
{ key: 'Rear Stationary', transformedValue: 'rear window' },
|
||||
{ key: 'Rear Slider', transformedValue: 'rear window' },
|
||||
{ key: 'Driver Front', transformedValue: 'driver side front door' },
|
||||
{ key: 'Driver Back ', transformedValue: 'driver side back door' },
|
||||
{ key: 'Driver Vent', transformedValue: 'driver side vent glass' },
|
||||
{ key: 'Driver Quarter', transformedValue: 'driver side quarter panel' },
|
||||
{ key: 'Driver SideDoor', transformedValue: 'driver side sliding door' },
|
||||
{ key: 'Passenger Front', transformedValue: 'passenger side front door' },
|
||||
{ key: 'Passenger Back', transformedValue: 'passenger side back door' },
|
||||
{ key: 'Passenger Vent', transformedValue: 'passenger side vent glass' },
|
||||
{ key: 'Passenger Quarter', transformedValue: 'passenger side quarter panel' },
|
||||
{ key: 'Passenger SlideDoor', transformedValue: 'passenger side sliding door' },
|
||||
]
|
||||
}
|
||||
|
||||
export function getCustomTransformValue(type, key) {
|
||||
const transformArray = customMappings[type.toLowerCase()];
|
||||
|
||||
if(transformArray === undefined) {
|
||||
return '';
|
||||
}
|
||||
// Gets an instance of a string where the dynamic portion of the text {custom:KeyName}
|
||||
// is replaced by a value from the above map.
|
||||
// If the value isn't found, return the original dynamic string without replacement
|
||||
export function getCustomTransformValue(dynamicString, key) {
|
||||
|
||||
const transformValue = transformArray.find(map => map.key === key.toLowerCase());
|
||||
|
||||
return transformValue === undefined ? '' : transformValue;
|
||||
}
|
||||
|
||||
export function getCustomTransformKey(value) {
|
||||
// Get array key from the dynamic string
|
||||
const regexExp = new RegExp("{(.*?):(.*?)}", "g");
|
||||
const matches = [...value.matchAll(regexExp)];
|
||||
const matches = [...dynamicString.matchAll(regexExp)];
|
||||
|
||||
if (matches.length === 0) {
|
||||
return '';
|
||||
return dynamicString;
|
||||
}
|
||||
|
||||
const key = matches[0][2];
|
||||
const arrayKey = matches[0][2];
|
||||
|
||||
return key;
|
||||
// Get the array of possible values based on the key name.
|
||||
const transformArray = customMappings[arrayKey.toLowerCase()];
|
||||
|
||||
if(transformArray === undefined) {
|
||||
return dynamicString;
|
||||
}
|
||||
|
||||
// Get the value where the name matches the key name, there should only be one so find() is used.
|
||||
const mapObject = transformArray.find(map => map.key.toLowerCase() === key.toLowerCase());
|
||||
|
||||
if(mapObject === undefined){
|
||||
return dynamicString;
|
||||
}
|
||||
|
||||
const finalString = dynamicString.replace(`{custom:${arrayKey}}`, mapObject.transformedValue);
|
||||
|
||||
return finalString
|
||||
}
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
|
||||
// TintMap with array keys by location, lowercase to avoid as much string mismatching as possible.
|
||||
// Src assumes you have a @/assets/img/tints/, making the final value @/assets/img/tints/{Src} in the markup.
|
||||
// See vehicle-parts for implementation example.
|
||||
const tintMap = {
|
||||
backglass: [
|
||||
rear: [
|
||||
// Blue Shade
|
||||
{ name: "blue shade, blue tint", src: "BackGlass-BlueShade-BlueTint.svg" },
|
||||
{ name: "blue shade, brown tint", src: "BackGlass-BlueShade-BrownTint.svg" },
|
||||
|
|
@ -71,11 +75,16 @@ const tintMap = {
|
|||
]
|
||||
}
|
||||
|
||||
export function getTintImage(glassType, colorString) {
|
||||
|
||||
if(tintMap[glassType.toLowerCase()] === undefined) {
|
||||
// Gets the tint image source string given the glass location, and the tint description (like 'Green Tint')
|
||||
// Use lowered strings here to try to avoid mismatch. Returns an empty string if array key doesn't exist.
|
||||
// Returns undefined if no items are found.
|
||||
export function getTintImage(glassLocation, colorString) {
|
||||
|
||||
if (tintMap[glassLocation.toLowerCase()] === undefined) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return tintMap[glassType.toLowerCase()].find(item => item.name == colorString.toLowerCase())
|
||||
const tintImageSource = tintMap[glassLocation.toLowerCase()].find(item => item.name.toLowerCase() == colorString.toLowerCase())
|
||||
|
||||
return tintImageSource;
|
||||
}
|
||||
|
|
@ -1,25 +1,31 @@
|
|||
<template>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<p>Select your current {{ glassName }} color:</p>
|
||||
<p>{{ colorQuestionText }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container nested-radio" v-for="(value, name, index) in featureListData" :key="index">
|
||||
|
||||
<div class="row my-2">
|
||||
<div class="col">
|
||||
<listCard v-model="selectedTint[name]" isRadio="true" isWide="true" :buttonImage="require(`@/assets/img/tints/${getTintImage(glassName, name)}`)" :buttonLabel="name" altText="" :buttonID="`${glassName}-${name}`" :groupName="`${glassName}`" @isCheckedChanged="ResetTintAndPartSelections()" />
|
||||
{{ selectedTint }}
|
||||
<listCard v-model="selectedTint[name]" :isRadio="true" :isWide="true" :buttonImage="
|
||||
require(`@/assets/img/tints/${getTintSourceImage(
|
||||
glassLocation,
|
||||
name
|
||||
)}`)
|
||||
" :buttonLabel="name" altText="" :buttonID="`${glassLocation}-${glassName}-${name}`" :groupName="`${glassLocation}-${glassName}`" @isCheckedChanged="ResetTintAndPartSelections()" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedTint[name] != undefined &&selectedTint[name].buttonId === `${glassName}-${name}`" class="row my-2">
|
||||
<div v-if="
|
||||
selectedTint[name] != undefined &&
|
||||
selectedTint[name].buttonId === `${glassLocation}-${glassName}-${name}`
|
||||
" class="row my-2">
|
||||
<div class="col">
|
||||
<buttonQuestion v-model="selectedPart[glassName]" buttonType="radio" class="radioQuestion" questionText="ok now select your features" :answers="value" textPosition="text-start" :loaderEnabled="false" isRequired="true" :groupName="`${glassName}-${name}`" />
|
||||
{{ selectedPart }}
|
||||
<buttonQuestion v-model="selectedPart[glassLocation]" buttonType="radio" class="radioQuestion" questionText="ok now select your features" :answers="value" textPosition="text-start" :loaderEnabled="false" :isRequired="true" :groupName="`${glassLocation}-${glassName}-${name}`" v-on:update:modelValue="EmitPartSelection($event)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -33,12 +39,12 @@ import {
|
|||
getTintImage
|
||||
} from "@/constants/tint-mapper";
|
||||
import {
|
||||
getCustomTransformValue,
|
||||
getCustomTransformKey,
|
||||
getCustomTransformValue
|
||||
} from "@/constants/dynamictext-mapper";
|
||||
|
||||
export default {
|
||||
name: "part-question",
|
||||
inheritAttrs: false,
|
||||
data() {
|
||||
return {
|
||||
glassColorQuestion: String,
|
||||
|
|
@ -50,6 +56,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
glassName: String,
|
||||
glassLocation: String,
|
||||
colorAnswers: Array,
|
||||
},
|
||||
components: {
|
||||
|
|
@ -58,18 +65,18 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
colorQuestionText() {
|
||||
return "Backglass";
|
||||
}
|
||||
return getCustomTransformValue(
|
||||
"Select your current {custom:glassName} color",
|
||||
`${this.glassLocation} ${this.glassName}`
|
||||
);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.featureListData = this.createFeatureListMap(this.colorAnswers);
|
||||
// const s = getCustomTransformKey('Select your current {custom:glassName} color')
|
||||
// const r = getCustomTransformValue(s, this.glassName);
|
||||
},
|
||||
methods: {
|
||||
initializeComponent(cmsContent, initialData) {
|
||||
this.glassColorQuestion = cmsContent.ColorQuestion;
|
||||
this.glassFeatureQuestion = cmsContent.FeatureQuestion;
|
||||
console.log("Im here");
|
||||
},
|
||||
|
||||
// Creates a map of the feature list data in the correct Name/Value
|
||||
|
|
@ -82,8 +89,8 @@ export default {
|
|||
|
||||
// Map the data to Name/Text object for ButtonQuestion
|
||||
const mappedItem = item.FeatureAnswers.reduce((featureArr, item) => {
|
||||
featureArr["Text"] = item.FeatureAnswerText;
|
||||
featureArr["Name"] = item.PartNumber;
|
||||
featureArr["Text"] = item.FeatureAnswerText; // Display to User
|
||||
featureArr["Name"] = item.PartNumber; // Backing Value
|
||||
|
||||
return featureArr;
|
||||
}, {});
|
||||
|
|
@ -97,18 +104,29 @@ export default {
|
|||
return tintMapByColor;
|
||||
},
|
||||
|
||||
// Gets tint images based on the glass type, and tint name
|
||||
getTintImage(glassType, tintColor) {
|
||||
const tintObject = getTintImage(glassType, tintColor);
|
||||
// Gets tint images based on the glass type, and tint name.
|
||||
// Returns an empty string if the src or object is undefined.
|
||||
getTintSourceImage(glassLocation, tintColor) {
|
||||
const tintSourceObject = getTintImage(glassLocation, tintColor);
|
||||
|
||||
return tintObject === undefined ? "" : tintObject.src;
|
||||
if (tintSourceObject === undefined || tintSourceObject.src == undefined) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return tintSourceObject.src;
|
||||
},
|
||||
|
||||
// Reset selections when tint changes for the same glass
|
||||
// Reset selections when tint changes for the same glass to ensure proper selection.
|
||||
ResetTintAndPartSelections() {
|
||||
this.selectedTint = {};
|
||||
this.selectedPart = {};
|
||||
},
|
||||
|
||||
// Emits selected part back to the parent vehicle-parts component
|
||||
// so it can have a object that contains all selected parts.
|
||||
EmitPartSelection(event) {
|
||||
this.$emit("update:modelValue", event);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,80 @@
|
|||
<template>
|
||||
<div class="container-fluid shadow rounded-3 p-0 position-relative">
|
||||
<funnelHeader ref="funnelHeader" />
|
||||
<vehicleBanner ref="vehicleBanner" :displayGenericVehicleImage=false />
|
||||
<funnelSubHeader ref="funnelSubHeader" />
|
||||
<funnelFooter ref="funnelFooter" @back-clicked="backButtonAction" />
|
||||
{{ glassParts }}
|
||||
<div v-for="(item, i) in Parts" :key="i">
|
||||
<partQuestion :glassName="item.glassName" :colorAnswers="item.colorAnswers" />
|
||||
<partQuestion :ref="`${refPrefix}-${item.glassLocation}`" v-model="glassParts[item.glassLocation + '-' + item.glassName]" :glassLocation="item.glassLocation" :glassName="item.glassName" :colorAnswers="item.colorAnswers" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import partQuestion from "@/layouts/vehicle-parts/part-question/part-question";
|
||||
import {
|
||||
fetchCmsContentForPage
|
||||
} from "@/helpers/cms-content-helper";
|
||||
import {
|
||||
settleAllPromises
|
||||
} from "@/helpers/layout-helper";
|
||||
import {
|
||||
storeActions
|
||||
} from "@/constants/store-actions";
|
||||
import store from "@/store";
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
|
||||
export default {
|
||||
name: "vehicle-parts",
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [{
|
||||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
}];
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
// Call the "next" function to complete the transition to this page.
|
||||
next((vm) => {
|
||||
|
||||
// vm.$refs.funnelHeader.initializeComponent(
|
||||
// resultMap.cmsContent.FunnelHeaderWidget
|
||||
// );
|
||||
|
||||
// vm.$refs.vehicleBanner.initializeComponent(
|
||||
// resultMap.cmsContent.VehicleBannerWidget
|
||||
// );
|
||||
// vm.$refs.funnelSubHeader.initializeComponent(
|
||||
// resultMap.cmsContent.FunnelSubHeaderWidget
|
||||
// );
|
||||
|
||||
// vm.$refs.funnelFooter.initializeComponent(
|
||||
// resultMap.cmsContent.FunnelFooterWidget
|
||||
// );
|
||||
|
||||
// Part Question dynamic component
|
||||
|
||||
|
||||
for (const key of Object.keys(vm.$refs)) {
|
||||
if (key.includes(vm.refPrefix) && vm.$refs[key][0] !== undefined) {
|
||||
const partQuestionComp = vm.$refs[key][0];
|
||||
|
||||
partQuestionComp.initializeComponent()
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
Parts: [
|
||||
{
|
||||
glassName: 'Backglass',
|
||||
Parts: [{
|
||||
glassLocation: 'Rear',
|
||||
glassName: 'Stationary',
|
||||
colorAnswers: [{
|
||||
ColorAnswerText: 'Green Tint',
|
||||
FeatureAnswers: [{
|
||||
|
|
@ -46,7 +106,8 @@ export default {
|
|||
]
|
||||
},
|
||||
{
|
||||
glassName: 'Windshield',
|
||||
glassLocation: 'Windshield',
|
||||
glassName: 'Single',
|
||||
colorAnswers: [{
|
||||
ColorAnswerText: 'Blue Tint',
|
||||
FeatureAnswers: [{
|
||||
|
|
@ -77,12 +138,17 @@ export default {
|
|||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
],
|
||||
glassParts: {},
|
||||
refPrefix: 'partQuestion'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
partQuestion,
|
||||
},
|
||||
mounted() {
|
||||
console.log("mounted!");
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" :data-focus-target="groupName" @click="handleChange(value)" v-model="checkValue" @change="handleCheckChange()" />
|
||||
<label :for="buttonID" class="d-flex w-100 align-items-center px-2 h-100" :class="getLabelClasses" tabindex="-1">
|
||||
<img :id="buttonImageId" :class="!isWide ? 'order-1' : 'ms-auto order-3'" :src="buttonImage" :alt="altText" />
|
||||
<p v-if="!isWide" class="small order-3" :class="isMultiSelect ? 'm-0' : 'mt-2 mb-0'">
|
||||
<p v-if=!isWide class="small order-3" :class="isMultiSelect ? 'm-0' : 'mt-2 mb-0'">
|
||||
{{buttonLabel}}
|
||||
</p>
|
||||
<p v-if="buttonLabelSubCopy && !isWide" class="fs-7 m-0 order-4 sub-copy">
|
||||
{{buttonLabelSubCopy}}
|
||||
</p>
|
||||
<div v-if="isWide" class="order-2">
|
||||
<div v-if=isWide class="order-2">
|
||||
<p class="m-0 small">{{ buttonLabel }}</p>
|
||||
<p v-if="buttonLabelSubCopy" class="m-0 fs-7 sub-copy">
|
||||
{{ buttonLabelSubCopy }}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export default {
|
|||
buttonLabel: String,
|
||||
buttonID: String,
|
||||
isRequired: Boolean,
|
||||
hasError: Boolean,
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: "",
|
||||
|
|
|
|||
Loading…
Reference in a new issue