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