This commit is contained in:
Kulbhushan Kaushik 2022-11-14 11:17:35 -05:00
parent 099ddea620
commit 7ecd40bdf3

View file

@ -1,253 +1,271 @@
<!-- 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 && answers && answers.length > 0" class="question-text d-flex"> <div v-if="questionText && answers && answers.length > 0" class="question-text d-flex">
<span class="fw-bold w-100">{{ questionText }}</span> <span class="fw-bold w-100">{{ questionText }}</span>
</div> </div>
<div class="w-100 d-flex justify-content-center"> <div class="w-100 d-flex justify-content-center">
<fieldset class="w-100" :aria-required=isRequired :class="getFieldSetClasses" :role="isMultiSelect ? 'group' : 'radiogroup'" :aria-labelledby="formatString(groupName)"> <fieldset
<legend class="sr-only" :data-focus-target="formatString(groupName)" :id="formatString(groupName)" tabindex="-1"> class="w-100"
{{ questionText }} :aria-required="isRequired"
{{(isMultiSelect && answers && answers.length > 1) ? 'Select one or more options below.' : 'Select an option below.' }} :class="getFieldSetClasses"
</legend> :role="isMultiSelect ? 'group' : 'radiogroup'"
<div :class="getComponentLoopWrapperClasses"> :aria-labelledby="formatString(groupName)">
<div :class="getComponentWrapperClasses" v-for="answer in answers" :key="answer.Name ? answer.Name : answer"> <legend
<component class="sr-only"
:is="buttonType" :data-focus-target="formatString(groupName)"
@isCheckedChanged="handleCheckedChanged" tabindex="-1"
:buttonID="answer.Name ? formatString(groupName) + '-' + answer.Name : formatString(groupName) + '-' + getAnswerString(answer, 'Text')" :id="formatString(groupName)">
:value="getValue(answer)" {{ questionText }}
:buttonLabel="answer.Text ? answer.Text : getAnswerString(answer, 'Name')" {{
:buttonLabelSubCopy="answer.SubText" isMultiSelect && answers && answers.length > 1
:textPosition="textPosition" ? "Select one or more options below."
:isMultiSelect="isMultiSelect" : "Select an option below."
:groupName="formatString(groupName)" }}
:selectingInitiatesLoad="selectingInitiatesLoad" </legend>
:loaderColor="loaderColor" <div :class="getComponentLoopWrapperClasses">
:loaderPosition="loaderPosition" <div
:isWide=isWide :class="getComponentWrapperClasses"
:isCashOrInsurance=isCashOrInsurance v-for="answer in buttonsInfo"
:isRequired=isRequired :key="answer.value ? answer.value : answer">
:buttonImage="answer.AnswerImageUrl" <component
:buttonImageId="answer.ImageId" :is="buttonTypeString"
:altText="answer.Name ? answer.Name : answer" :buttonLabel="answer.buttonLabel"
screenReaderOnlyText="(opens new window)" :buttonLabelSubCopy="answer.buttonLabelSubCopy"
:colLength="getColLength" :buttonBodyCopy="answer.buttonBodyCopy"
:selectedValues="selectedValues" :buttonAuxillaryCopy="answer.buttonAuxillaryCopy"
data-test="button" :buttonFooterCopy="answer.buttonFooterCopy"
:validationRules="validationRules" :buttonImage="answer.buttonImage"
:class="[suppressError ? 'alertError' : '' , isCashOrInsurance ? 'radio-fancy' : '']" :buttonImageId="answer.buttonImageId"
:valueToLogType="valueToLogType" :groupName="answer.groupName"
/> :isMultiSelect="isMultiSelect"
<!-- For nested questions --> :value="answer.value"
<transition name="fade" mode="out-in"> :selectingInitiatesLoad="selectingInitiatesLoad"
<div v-if="typeof selectedValues == 'string' && selectedValues == answer.Name"> :isWide="isWide"
<slot></slot> :validationRules="validationRules"
</div> :textPosition="textPosition"
</transition> :additionalButtonStyling="additionalButtonStyling"
</div> :lastValuePushedToGa="lastValuePushedToGa"
</div> :setLastValuePushedToGa="setLastValuePushedToGa"
</fieldset> v-model="selectedValues" />
<!-- For nested questions -->
<transition name="fade" mode="out-in">
<div
v-if="
typeof selectedValues == 'string' &&
selectedValues == answer.value
">
<slot></slot>
</div>
</transition>
</div>
</div>
</fieldset>
</div> </div>
<div class="row form-test-error mt-1"> <div class="row form-test-error mt-1">
<error-message :name="formatString(groupName)" v-if="!suppressError"></error-message> <error-message :name="formatString(groupName)" v-if="!suppressError"></error-message>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import listButton from "@/ux-components/list-button/list-button"; import listButton from "@/ux-components/list-button/list-button";
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal"; import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
import listCard from "@/ux-components/list-card/list-card"; import listCard from "@/ux-components/list-card/list-card";
import { ErrorMessage } from 'vee-validate'; import radio from "@/ux-components/radio/radio";
import radio from "@/ux-components/radio/radio"; import { ErrorMessage } from "vee-validate";
export default { export default {
name: "buttonQuestion", name: "buttonQuestion",
props: { props: {
buttonType: { buttonTypeString: {
type: String, type: String,
default: "listButton", default: "listButton",
},
buttonTypeObject: {
type: Object,
default: null,
}, },
isMultiSelect: Boolean, isMultiSelect: Boolean,
groupName: String, groupName: String,
questionText: String, questionText: String,
answers: Array, answers: Array,
textPosition: { textPosition: {
type: String, type: String,
default: "text-center", default: "text-center",
}, },
selectingInitiatesLoad: Boolean, selectingInitiatesLoad: Boolean,
loaderColor: { loaderColor: {
type: String, type: String,
default: "blue", default: "blue",
}, },
loaderPosition: { loaderPosition: {
type: String, type: String,
default: "right", default: "right",
}, },
isRequired: Boolean, isRequired: Boolean,
isOverflowScrollable: Boolean, isOverflowScrollable: Boolean,
isWide: Boolean, isWide: Boolean,
isCashOrInsurance: Boolean, isCashOrInsurance: Boolean,
modelValue: [Array, String], modelValue: [Array, Number, String],
value: [Number, String],
validationRules: String, validationRules: String,
suppressError: Boolean, suppressError: Boolean,
useTextForValue: Boolean, useTextForValue: Boolean,
valueToLogType: String, valueToLogType: String,
}, additionalButtonStyling: String,
computed: { },
beforeMount() {
if (this.buttonTypeObject) {
this.$options.components[this.buttonTypeString] = this.buttonTypeObject;
}
},
data() {
return {
lastValuePushedToGa: null,
};
},
computed: {
getFieldSetClasses() { getFieldSetClasses() {
if (this.isOverflowScrollable) { if (this.isOverflowScrollable) {
return "container-fluid overflow-scroll position-absolute px-5 pt-1 py-0"; return "container-fluid overflow-scroll position-absolute px-5 pt-1 py-0";
} } else if (this.buttonTypeString == "listCard") {
else if (this.buttonType == "listCard") { return "w-100";
return "w-100"; } else {
} return "";
else { }
return "";
}
}, },
getComponentLoopWrapperClasses() { getComponentLoopWrapperClasses() {
let classes; let classes;
switch (this.buttonType) { switch (this.buttonTypeString) {
case "listButton": case "listButton":
classes = "w-100"; classes = "w-100";
break; break;
case "listButtonHorizontal": case "listButtonHorizontal":
classes = "d-flex flex-row p-0"; classes = "d-flex flex-row p-0";
break; break;
case 'listCard': case "listCard":
classes = "row g-2 justify-content-center"; classes = "row g-2 justify-content-center";
break; if (this.isWide) {
case 'radio': classes += " flex-column";
classes = 'ui-radio d-flex' }
break; break;
} case "radio":
return classes; classes = "ui-radio d-flex";
break;
case "servicePackageRadio":
classes = "package-main";
break;
}
return classes;
}, },
getComponentWrapperClasses() { getComponentWrapperClasses() {
let classes = ""; let classes = "";
classes += this.isWide ? "col-12" : "col"; classes += this.isWide ? "col-12" : "col";
if (this.buttonType == "radio") { if (this.buttonTypeString == "radio") {
classes += " radio-button-container"; classes += " radio-button-container";
} } else if (this.buttonTypeString == "servicePackageRadio") {
classes = "package-wrapper";
return classes; }
return classes;
}, },
getColLength(){ buttonsInfo() {
if(this.isWide) { return (Array.isArray(this.answers) ? this.answers : [])?.map((answer) => ({
return "12" buttonLabel: answer.buttonLabel ?? answer.Text ?? answer,
} else { altText: answer.altText ?? (answer.Name ? answer.Name : answer),
return ""; buttonLabelSubCopy: answer.buttonLabelSubCopy ?? answer.SubText,
} buttonBodyCopy: answer.buttonBodyCopy ?? answer.buttonBodyCopy,
buttonAuxillaryCopy: answer.buttonAuxillaryCopy ?? answer.buttonAuxillaryCopy,
buttonFooterCopy: answer.buttonFooterCopy ?? answer.buttonFooterCopy,
buttonImage: answer.buttonImage ?? answer.AnswerImageUrl,
buttonImageId: answer.buttonImageId ?? answer.ImageId,
groupName: this.formatString(this.groupName),
value:
answer.value ??
(this.useTextForValue && answer.Text ? answer.Text : answer.Name) ??
(typeof answer !== "object" ? answer : null),
}));
}, },
selectedValues: { selectedValues: {
get: function() { get() {
return this.modelValue; return this.modelValue;
}, },
set: function(newValue) { set(selectedAnswers) {
this.$emit("update:modelValue", newValue); this.$emit("update:modelValue", selectedAnswers);
} },
}, },
}, },
methods: { methods: {
formatString(str) { formatString(str) {
return str.replace(" ", "-"); return str?.replaceAll(" ", "-");
}, },
getValue(answer){ setLastValuePushedToGa(lastValuePushedToGa) {
if (this.useTextForValue) { return answer.Text } this.lastValuePushedToGa = lastValuePushedToGa;
return answer.Name ? answer.Name : answer;
}, },
getAnswerString(answer, prop = "Name") { },
switch (typeof answer) { components: {
case "string":
case "number":
case "boolean":
return this.formatString(answer.toString());
default:
return answer[prop] ? this.formatString(answer[prop]) : this.formatString(answer.toString());
}
},
handleCheckedChanged(val) {
if(this.selectingInitiatesLoad) {
this.selectedValues = val.value;
} else {
if(this.isMultiSelect) {
const newSelectedValues = this.selectedValues;
val.checkValue ? newSelectedValues.push(val.value) : newSelectedValues.splice(newSelectedValues.indexOf(val.value), 1);
this.selectedValues = newSelectedValues;
}
else if (Array.isArray(this.selectedValues)) {
this.selectedValues[0] = val.value;
const temp = this.selectedValues;
this.selectedValues = temp;
}
else {
this.selectedValues = val.value;
}
}
this.$emit("isCheckedChanged", val);
},
},
components: {
listButton, listButton,
listButtonHorizontal, listButtonHorizontal,
listCard, listCard,
ErrorMessage, ErrorMessage,
radio, radio,
}, },
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.button-question-overflow { .button-question-overflow {
height: calc(100vh - 274px); height: calc(100vh - 274px);
.overflow-scroll { .overflow-scroll {
// Height will be determined by overall height of content above list // Height will be determined by overall height of content above list
height: calc(100% - 314px); height: calc(100% - 314px);
overflow-x: hidden !important; overflow-x: hidden !important;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
}
} }
.button-question { }
color: $black; .button-question {
color: $black;
.radio-button-container {
.radio-button-container {
&:not(:last-child) { &:not(:last-child) {
padding-bottom: map-get($spacers, 2); padding-bottom: map-get($spacers, 2);
}
}
}
.question-text {
margin-top: 1.5rem;
margin-bottom: 1rem;
font-size: 1rem;
line-height: 1.625rem;
& > span {
text-align: center;
}
}
.vehicle-parts {
.question-text {
span {
font-size: 0.875rem;
text-align: left;
margin: 0 0 0.5rem 0;
} }
}
} }
.question-text { .question-text {
margin-top: 1.5rem;
margin-bottom: 1rem;
font-size: 1rem;
line-height: 1.5rem;
& > span {
text-align: center;
}
}
.vehicle-parts {
.question-text {
span {
font-size: .875rem;
text-align: left;
margin: 0 0 .5rem 0;
}
}
.question-text {
margin: 0; margin: 0;
}
fieldset {
.ui-radio {
margin: 0;
}
}
} }
</style> fieldset {
.ui-radio {
margin: 0;
}
}
}
</style>