CSR-343 WIP

This commit is contained in:
Katie 2022-06-27 08:40:56 -04:00
parent f0748c4c0b
commit 9d7c6fc1fc
4 changed files with 313 additions and 275 deletions

View file

@ -1,19 +1,17 @@
<!-- Documented in confluence https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Component --> <!-- Documented in confluence https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Component -->
<template> <template>
<div :class="isOverflowScrollable ? 'button-question button-question-overflow' : 'button-question'"> <div :class="isOverflowScrollable ? 'button-question button-question-overflow' : 'button-question'">
<div v-if="questionText" class="question-text d-flex"> <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="fs-5 fw-bold w-100">{{ questionText }}</span>
</div> </div>
<div class="w-100 d-flex justify-content-center"> <div class="w-100 justify-content-center">
<fieldset class="w-100" :aria-required=isRequired :class="getFieldSetClasses" :role="isMultiSelect ? 'group' : 'radiogroup'" :aria-labelledby="groupName"> <fieldset class="w-100" :aria-required=isRequired :class="getFieldSetClasses" :role="isMultiSelect ? 'group' : 'radiogroup'" :aria-labelledby="groupName">
<legend class="sr-only" :data-focus-target="groupName" :id="groupName" tabindex="-1"> <legend class="sr-only" :data-focus-target="groupName" :id="groupName" tabindex="-1">
{{(isMultiSelect && answers && answers.length > 1) ? 'Select one or more options below.' : 'Select an option below.' }} {{(isMultiSelect && answers && answers.length > 1) ? 'Select one or more options below.' : 'Select an option below.' }}
</legend> </legend>
<div :class="getComponentWrapperClasses"> <div :class="getComponentWrapperClasses" v-for="answer in answers" :key="answer.Name ? answer.Name : answer">
<component <component
:is="buttonType" :is="buttonType"
v-for="answer in answers"
:key="answer.Name ? answer.Name : answer"
@isCheckedChanged="handleCheckedChanged" @isCheckedChanged="handleCheckedChanged"
:buttonID="answer.Name ? groupName + '-' + answer.Name : groupName + '-' + answer" :buttonID="answer.Name ? groupName + '-' + answer.Name : groupName + '-' + answer"
:value="getValues(answer)" :value="getValues(answer)"
@ -38,6 +36,12 @@
:class="[suppressError ? 'alertError' : '']" :class="[suppressError ? 'alertError' : '']"
:clearOnUnmount="clearOnUnmount" :clearOnUnmount="clearOnUnmount"
/> />
<!-- For nested questions -->
<transition name="fade" mode="out-in">
<div v-if="typeof selectedValues == 'string' && selectedValues == answer.Name">
<slot></slot>
</div>
</transition>
</div> </div>
</fieldset> </fieldset>
</div> </div>
@ -81,14 +85,14 @@ export default {
isRequired: Boolean, isRequired: Boolean,
isOverflowScrollable: Boolean, isOverflowScrollable: Boolean,
isWide: Boolean, isWide: Boolean,
modelValue: Array, modelValue: [Array, String],
validationRules: String, validationRules: String,
suppressError: Boolean, suppressError: Boolean,
useTextForValue: Boolean, useTextForValue: Boolean,
clearOnUnmount: { clearOnUnmount: {
type: Boolean, type: Boolean,
default: true default: true
} },
}, },
computed: { computed: {
getFieldSetClasses() { getFieldSetClasses() {
@ -135,6 +139,7 @@ export default {
if (this.useTextForValue){ if (this.useTextForValue){
return answer.Text return answer.Text
} }
console.log(answer.Name ? answer.Name : answer)
return answer.Name ? answer.Name : answer; return answer.Name ? answer.Name : answer;
}, },
handleCheckedChanged(val) { handleCheckedChanged(val) {
@ -146,6 +151,9 @@ export default {
val.checkValue ? newSelectedValues.push(val.value) : newSelectedValues.splice(newSelectedValues.indexOf(val.value), 1); val.checkValue ? newSelectedValues.push(val.value) : newSelectedValues.splice(newSelectedValues.indexOf(val.value), 1);
this.selectedValues = newSelectedValues; this.selectedValues = newSelectedValues;
} }
else {
this.selectedValues = val.value;
}
} }
}, },
}, },

View file

@ -4,76 +4,66 @@
<p class="mb-0 color-question-text">{{ colorQuestionText }}</p> <p class="mb-0 color-question-text">{{ colorQuestionText }}</p>
</div> </div>
</div> </div>
{{ featureListData }}
<br />
{{ tintSelectionOptions }}
<br />
{{ selectedTint }}
{{ selectedPart }}
<div <div class="container nested-radio">
class="container nested-radio"
v-for="(value, name, index) in featureListData"
:key="index"
>
<div class="row my-2"> <div class="row my-2">
<div class="col"> <div class="col">
<listCard <buttonQuestion
v-model="selectedTint[name]" v-model="selectedTint"
:value="`${glassLocation}-${glassName}-${name}`" :answers="tintSelectionOptions"
:isRadio="true" :nestedAnswers="featureListData[selectedTint]"
buttonType="listCard"
:isWide="true" :isWide="true"
:buttonImage="
require(`@/assets/img/tints/${getTintSourceImage(
glassLocation,
name
)}`)
"
:buttonLabel="name"
altText="" altText=""
isRequired isRequired
:buttonID="`${glassLocation}-${glassName}-${name}`"
:groupName="`${glassLocation}-${glassName}`" :groupName="`${glassLocation}-${glassName}`"
@isCheckedChanged="ResetTintAndPartSelections()" @isCheckedChanged="ResetTintAndPartSelections()"
:validationRules="validationRules" :validationRules="validationRules"
/>
<div class="row form-test-error mt-1">
<error-message :name="`${glassLocation}-${glassName}`" v-if="!suppressError"></error-message>
</div>
</div>
</div>
<transition name="fade" mode="out-in">
<div
v-if="
selectedTint[name] != undefined &&
selectedTint[name].buttonId ===
`${glassLocation}-${glassName}-${name}`
"
class="row my-2"
aria-live="polite"
> >
<transition name="fade" mode="out-in">
<div class="row my-2" aria-live="polite">
<div class="col"> <div class="col">
<buttonQuestion <buttonQuestion
v-model="selectedPart[glassLocation]" v-model="selectedPart"
buttonType="radio" buttonType="radio"
class="radioQuestion" class="radioQuestion"
:questionText="glassFeatureQuestion" :questionText="glassFeatureQuestion"
:answers="value" :answers="featureListData[selectedTint]"
textPosition="text-start" textPosition="text-start"
:loaderEnabled="false" :loaderEnabled="false"
isRequired isRequired
:groupName="`${glassLocation}-${glassName}-${name}`" :groupName="`${glassLocation}-${glassName}-${selectedTint}`"
:validationRules="validationRules" :validationRules="validationRules"
/> />
</div> </div>
</div> </div>
</transition> </transition>
</buttonQuestion>
</div>
</div>
</div>
<div class="row form-test-error mt-1">
<!-- <error-message
:name="`${glassLocation}-${glassName}`"
v-if="!suppressError"
></error-message> -->
</div> </div>
</template> </template>
<script> <script>
// Components // Components
import listCard from "@/ux-components/list-card/list-card";
import buttonQuestion from "@/common-components/button-question/button-question"; import buttonQuestion from "@/common-components/button-question/button-question";
// Supporting files // Supporting files
import { getTintImage } from "@/constants/tint-mapper"; import { getTintImage } from "@/constants/tint-mapper";
import { getCustomTransformValue } from "@/constants/dynamictext-mapper"; import { getCustomTransformValue } from "@/constants/dynamictext-mapper";
import { ErrorMessage } from 'vee-validate'; // import { ErrorMessage } from "vee-validate";
export default { export default {
name: "glass-part-question", name: "glass-part-question",
@ -82,7 +72,7 @@ export default {
return { return {
glassColorQuestion: "", glassColorQuestion: "",
glassFeatureQuestion: "", glassFeatureQuestion: "",
selectedTint: {}, // v-model for the list card selections selectedTint: "",
}; };
}, },
props: { props: {
@ -96,9 +86,8 @@ export default {
this.LoadPreselectedValues(); this.LoadPreselectedValues();
}, },
components: { components: {
listCard,
buttonQuestion, buttonQuestion,
ErrorMessage, // ErrorMessage,
}, },
computed: { computed: {
colorQuestionText() { colorQuestionText() {
@ -108,11 +97,28 @@ export default {
); );
}, },
tintSelectionOptions() {
let tintOptions = [];
Object.keys(this.featureListData).forEach((tintOption) => {
tintOptions.push({
Name: tintOption,
Text: tintOption,
AnswerImageUrl: require(`@/assets/img/tints/${this.getTintSourceImage(
this.glassLocation,
tintOption
)}`),
});
});
return tintOptions;
},
selectedPart: { selectedPart: {
get: function () { get: function () {
return this.modelValue; return this.modelValue;
}, },
set: function (newValue) { set: function (newValue) {
console.log("modelValue: " + newValue)
this.$emit("update:modelValue", newValue); this.$emit("update:modelValue", newValue);
}, },
}, },
@ -126,12 +132,15 @@ export default {
arr[itemColor] = arr[itemColor] || []; arr[itemColor] = arr[itemColor] || [];
// Map the data to Name/Text object for ButtonQuestion // Map the data to Name/Text object for ButtonQuestion
const mappedItem = item.FeatureAnswers.reduce((featureArr, item) => { const mappedItem = item.FeatureAnswers.reduce(
(featureArr, item) => {
featureArr["Text"] = item.FeatureAnswerText; // Display to User featureArr["Text"] = item.FeatureAnswerText; // Display to User
featureArr["Name"] = item.PartNumber; // Backing Value featureArr["Name"] = item.PartNumber; // Backing Value
return featureArr; return featureArr;
}, {}); },
{}
);
// Add onto the final object // Add onto the final object
arr[itemColor].push(mappedItem); arr[itemColor].push(mappedItem);
@ -149,8 +158,10 @@ export default {
methods: { methods: {
// Initialize the component data // Initialize the component data
initializeComponent(cmsContent) { initializeComponent(cmsContent) {
this.glassColorQuestion = cmsContent.ColorQuestionWidget.QuestionText; this.glassColorQuestion =
this.glassFeatureQuestion = cmsContent.FeatureQuestionWidget.QuestionText; cmsContent.ColorQuestionWidget.QuestionText;
this.glassFeatureQuestion =
cmsContent.FeatureQuestionWidget.QuestionText;
}, },
// Gets tint images based on the glass type, and tint name. // Gets tint images based on the glass type, and tint name.
@ -158,7 +169,10 @@ export default {
getTintSourceImage(glassLocation, tintColor) { getTintSourceImage(glassLocation, tintColor) {
const tintSourceObject = getTintImage(glassLocation, tintColor); const tintSourceObject = getTintImage(glassLocation, tintColor);
if (tintSourceObject === undefined || tintSourceObject.src == undefined) { if (
tintSourceObject === undefined ||
tintSourceObject.src == undefined
) {
return ""; return "";
} }
@ -168,7 +182,7 @@ export default {
// Reset selections when tint changes for the same glass to ensure proper selection. // Reset selections when tint changes for the same glass to ensure proper selection.
// Also checks if only a single part is present for the tint. // Also checks if only a single part is present for the tint.
ResetTintAndPartSelections() { ResetTintAndPartSelections() {
this.selectedTint = {}; this.selectedTint = "";
this.selectedPart = {}; this.selectedPart = {};
this.AutoSelectIfSinglePart(); this.AutoSelectIfSinglePart();
}, },
@ -183,7 +197,8 @@ export default {
if ( if (
currentGlassSelection.glassName === this.glassName && currentGlassSelection.glassName === this.glassName &&
currentGlassSelection.glassLocation === this.glassLocation currentGlassSelection.glassLocation ===
this.glassLocation
) { ) {
if (currentGlassSelection.parts.length === 1) { if (currentGlassSelection.parts.length === 1) {
this.selectedPart = { this.selectedPart = {
@ -206,16 +221,18 @@ export default {
this.$store.getters.lineItems.glassParts; this.$store.getters.lineItems.glassParts;
Object.keys(alreadyPopulatedPartsData).forEach((key) => { Object.keys(alreadyPopulatedPartsData).forEach((key) => {
const partNumber = alreadyPopulatedPartsData[key].partNumber; const partNumber =
alreadyPopulatedPartsData[key].partNumber;
const tintColor = alreadyPopulatedPartsData[key].color; const tintColor = alreadyPopulatedPartsData[key].color;
Object.keys(this.modelValue).forEach((key) => { Object.keys(this.modelValue).forEach((key) => {
if (this.modelValue[key][0] === partNumber) { if (this.modelValue[key][0] === partNumber) {
this.selectedTint[tintColor] = { this.selectedTint = tintColor;
buttonId: `${this.glassLocation}-${this.glassName}-${tintColor}`, // this.selectedTint[tintColor] = {
checkValue: "", // buttonId: `${this.glassLocation}-${this.glassName}-${tintColor}`,
value: `${this.glassLocation}-${this.glassName}-${tintColor}`, // checkValue: "",
}; // value: `${this.glassLocation}-${this.glassName}-${tintColor}`,
// };
} }
}); });
}); });

View file

@ -170,41 +170,54 @@ methods: {
// Compile all selected parts from the page. // Compile all selected parts from the page.
for (let [key, value] of Object.entries(this.glassParts)) { for (let [key, value] of Object.entries(this.glassParts)) {
for (let [glassKey, glassValue] of Object.entries(value)) { selectedGlassPartNumbers.push(value);
selectedGlassPartNumbers.push(glassValue[0]); // for (let [glassKey, glassValue] of Object.entries(value)) {
} // selectedGlassPartNumbers.push(glassValue[0]);
// }
} }
console.log(this.glassParts)
console.log(selectedGlassPartNumbers)
console.log(this.PartsFromApi.partsOrQuestions)
// Match them to the parts from the API. // Match them to the parts from the API.
for (let [key, value] of Object.entries( for (let [key, value] of Object.entries(this.PartsFromApi.partsOrQuestions)) {
this.PartsFromApi.partsOrQuestions // const partsForGlassPart = value
)) {
for (let [partKey, partValue] of Object.entries(value.parts)) {
const currentPart =
this.PartsFromApi.partsOrQuestions[key].parts[partKey];
const isMatched = selectedGlassPartNumbers.some( const isMatched = selectedGlassPartNumbers.some(
(p) => p === currentPart.partNumber (p) => p === value.partNumber
); );
if (isMatched) { if (isMatched) {
matchedParts.push(currentPart); matchedParts.push(currentPart);
} }
// for (let [partKey, partValue] of Object.entries(value.parts)) {
// const currentPart = this.PartsFromApi.partsOrQuestions[key].parts[partKey];
// const isMatched = selectedGlassPartNumbers.some(
// (p) => p === currentPart.partNumber
// );
// if (isMatched) {
// matchedParts.push(currentPart);
// }
// }
} }
}
console.log(matchedParts)
// If no parts could be matched, throw an error. // If no parts could be matched, throw an error.
if (matchedParts.length === 0) { if (matchedParts.length === 0) {
throw new Error("Could not match any parts to the selected parts"); throw new Error("Could not match any parts to the selected parts");
} }
// Save parts to the store. // // Save parts to the store.
store.commit(storeMutations.UPDATE_GLASS_PARTS, matchedParts); // store.commit(storeMutations.UPDATE_GLASS_PARTS, matchedParts);
// Navigate to the next page. // // Navigate to the next page.
this.$router.navigateAfterSave( // this.$router.navigateAfterSave(
this.navigationScenarios.SELECTED_PARTS, // this.navigationScenarios.SELECTED_PARTS,
this.$route // this.$route
); // );
}, },
resetDependentState() { resetDependentState() {

View file

@ -86,7 +86,7 @@ export default {
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>yu78zas
.form-check { .form-check {
.form-check-input { .form-check-input {
border: 1px solid $gray-500; border: 1px solid $gray-500;