This commit is contained in:
FrankRua 2022-02-22 15:33:28 -05:00
parent d9dc1eeb7e
commit 32a7cd077d
7 changed files with 172 additions and 69 deletions

View file

@ -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"

View file

@ -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
}

View file

@ -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;
}

View file

@ -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>

View file

@ -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;

View file

@ -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 }}

View file

@ -35,6 +35,7 @@ export default {
buttonLabel: String,
buttonID: String,
isRequired: Boolean,
hasError: Boolean,
value: {
type: [String, Number],
default: "",