CSR-762 Add mini test
This commit is contained in:
parent
0ee3bb672a
commit
6e901a6918
6 changed files with 276 additions and 39 deletions
|
|
@ -1,18 +1,60 @@
|
||||||
<!-- 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
|
||||||
<div v-if="questionText && answers && answers.length > 0" class="question-text d-flex">
|
: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>
|
||||||
|
|
||||||
|
selectedValues: {{ selectedValues }}
|
||||||
<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"
|
||||||
|
: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 }}
|
{{ questionText }}
|
||||||
{{(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="getComponentLoopWrapperClasses">
|
<div :class="getComponentLoopWrapperClasses">
|
||||||
<div :class="getComponentWrapperClasses" v-for="answer in answers" :key="answer.Name ? answer.Name : answer">
|
<div
|
||||||
|
:class="getComponentWrapperClasses"
|
||||||
|
v-for="answer in answers"
|
||||||
|
:key="answer.Name ? answer.Name : answer"
|
||||||
|
>
|
||||||
<component
|
<component
|
||||||
|
:is="buttonType"
|
||||||
|
:buttonLabel="
|
||||||
|
answer.Text ? answer.Text : getAnswerString(answer, 'Name')
|
||||||
|
"
|
||||||
|
:buttonLabelSubCopy="answer.SubText"
|
||||||
|
:isMultiSelect="isMultiSelect"
|
||||||
|
:groupName="groupName"
|
||||||
|
:value="answer.Value"
|
||||||
|
:modelValue="modelValue"
|
||||||
|
@change="e => handleSelectionChange(e, answer.Value)"
|
||||||
|
/>
|
||||||
|
<!-- <component
|
||||||
:is="buttonType"
|
:is="buttonType"
|
||||||
@isCheckedChanged="handleCheckedChanged"
|
@isCheckedChanged="handleCheckedChanged"
|
||||||
:buttonID="answer.Name ? formatString(groupName) + '-' + answer.Name : formatString(groupName) + '-' + getAnswerString(answer, 'Text')"
|
:buttonID="answer.Name ? formatString(groupName) + '-' + answer.Name : formatString(groupName) + '-' + getAnswerString(answer, 'Text')"
|
||||||
|
|
@ -38,10 +80,15 @@
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
:class="[suppressError ? 'alertError' : '' , isCashOrInsurance ? 'radio-fancy' : '']"
|
:class="[suppressError ? 'alertError' : '' , isCashOrInsurance ? 'radio-fancy' : '']"
|
||||||
:valueToLogType="valueToLogType"
|
:valueToLogType="valueToLogType"
|
||||||
/>
|
/> -->
|
||||||
<!-- For nested questions -->
|
<!-- For nested questions -->
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<div v-if="typeof selectedValues == 'string' && selectedValues == answer.Name">
|
<div
|
||||||
|
v-if="
|
||||||
|
typeof selectedValues == 'string' &&
|
||||||
|
selectedValues == answer.Name
|
||||||
|
"
|
||||||
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
@ -50,7 +97,10 @@
|
||||||
</fieldset>
|
</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>
|
||||||
|
|
@ -59,8 +109,9 @@
|
||||||
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 { ErrorMessage } from "vee-validate";
|
||||||
import radio from "@/ux-components/radio/radio";
|
import radio from "@/ux-components/radio/radio";
|
||||||
|
import testButton from "@/common-components/test-button.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "buttonQuestion",
|
name: "buttonQuestion",
|
||||||
|
|
@ -90,7 +141,8 @@ export default {
|
||||||
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,
|
||||||
|
|
@ -100,11 +152,9 @@ export default {
|
||||||
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.buttonType == "listCard") {
|
||||||
else if (this.buttonType == "listCard") {
|
|
||||||
return "w-100";
|
return "w-100";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -117,11 +167,11 @@ export default {
|
||||||
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;
|
break;
|
||||||
case 'radio':
|
case "radio":
|
||||||
classes = 'ui-radio d-flex'
|
classes = "ui-radio d-flex";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return classes;
|
return classes;
|
||||||
|
|
@ -129,7 +179,7 @@ export default {
|
||||||
getComponentWrapperClasses() {
|
getComponentWrapperClasses() {
|
||||||
let classes = "";
|
let classes = "";
|
||||||
|
|
||||||
classes += this.isWide ? "col-12" : "col";
|
classes += this.isWid ? "col-12" : "col";
|
||||||
|
|
||||||
if (this.buttonType == "radio") {
|
if (this.buttonType == "radio") {
|
||||||
classes += " radio-button-container";
|
classes += " radio-button-container";
|
||||||
|
|
@ -137,28 +187,31 @@ export default {
|
||||||
|
|
||||||
return classes;
|
return classes;
|
||||||
},
|
},
|
||||||
getColLength(){
|
getColLength() {
|
||||||
if(this.isWide) {
|
if (this.isWide) {
|
||||||
return "12"
|
return "12";
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectedValues: {
|
selectedValues: {
|
||||||
get: function() {
|
get: function () {
|
||||||
return this.modelValue;
|
return this.modelValue;
|
||||||
},
|
},
|
||||||
set: function(newValue) {
|
set: function (newValue) {
|
||||||
this.$emit("update:modelValue", newValue);
|
// this.$emit("update:modelValue", newValue);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatString(str) {
|
formatString(str) {
|
||||||
return str.replace(" ", "-");
|
console.log(str);
|
||||||
|
return str?.replace(" ", "-");
|
||||||
},
|
},
|
||||||
getValue(answer){
|
getValue(answer) {
|
||||||
if (this.useTextForValue) { return answer.Text }
|
if (this.useTextForValue) {
|
||||||
|
return answer.Text;
|
||||||
|
}
|
||||||
return answer.Name ? answer.Name : answer;
|
return answer.Name ? answer.Name : answer;
|
||||||
},
|
},
|
||||||
getAnswerString(answer, prop = "Name") {
|
getAnswerString(answer, prop = "Name") {
|
||||||
|
|
@ -168,24 +221,49 @@ export default {
|
||||||
case "boolean":
|
case "boolean":
|
||||||
return this.formatString(answer.toString());
|
return this.formatString(answer.toString());
|
||||||
default:
|
default:
|
||||||
return answer[prop] ? this.formatString(answer[prop]) : this.formatString(answer.toString());
|
return answer[prop]
|
||||||
|
? this.formatString(answer[prop])
|
||||||
|
: this.formatString(answer.toString());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleCheckedChanged(val) {
|
handleCheckedChanged(val) {
|
||||||
if(this.selectingInitiatesLoad) {
|
if (this.selectingInitiatesLoad) {
|
||||||
this.selectedValues = val.value;
|
this.selectedValues = val.value;
|
||||||
} else {
|
} else {
|
||||||
if(Array.isArray(this.selectedValues)) {
|
if (Array.isArray(this.selectedValues)) {
|
||||||
const newSelectedValues = this.selectedValues;
|
const newSelectedValues = this.selectedValues;
|
||||||
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 {
|
||||||
else {
|
|
||||||
this.selectedValues = val.value;
|
this.selectedValues = val.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.$emit("isCheckedChanged", val);
|
this.$emit("isCheckedChanged", val);
|
||||||
},
|
},
|
||||||
|
handleSelectionChange(event, value) {
|
||||||
|
console.log(value)
|
||||||
|
console.log("BQ handleSelectionChange: ", event)
|
||||||
|
let isChecked = event.target.checked;
|
||||||
|
if (this.isMultiSelect && this.modelValue instanceof Array) {
|
||||||
|
let newValue = [...this.modelValue];
|
||||||
|
const toggledValue = event.target.value;
|
||||||
|
console.log("A: ", this.modelValue)
|
||||||
|
console.log("isChecked: ", isChecked)
|
||||||
|
console.log("value: ", event.target.value)
|
||||||
|
if (isChecked) {
|
||||||
|
newValue.push(toggledValue);
|
||||||
|
} else {
|
||||||
|
newValue.splice(newValue.indexOf(toggledValue), 1);
|
||||||
|
}
|
||||||
|
console.log("handleCheckboxChange: ", newValue);
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
} else {
|
||||||
|
console.log("handleRadioChange: ", isChecked);
|
||||||
|
this.$emit("update:modelValue", value);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
listButton,
|
listButton,
|
||||||
|
|
@ -193,6 +271,7 @@ export default {
|
||||||
listCard,
|
listCard,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
radio,
|
radio,
|
||||||
|
testButton,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -231,9 +310,9 @@ export default {
|
||||||
.vehicle-parts {
|
.vehicle-parts {
|
||||||
.question-text {
|
.question-text {
|
||||||
span {
|
span {
|
||||||
font-size: .875rem;
|
font-size: 0.875rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin: 0 0 .5rem 0;
|
margin: 0 0 0.5rem 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.question-text {
|
.question-text {
|
||||||
|
|
|
||||||
35
src/common-components/test-button.vue
Normal file
35
src/common-components/test-button.vue
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<template>
|
||||||
|
<label :class="{ classNames }">
|
||||||
|
value: {{value}} <br/>
|
||||||
|
modelValue: {{modelValue}} <br/>
|
||||||
|
isChecked: {{isChecked}} <br/>
|
||||||
|
<input
|
||||||
|
v-if="isMultiSelect"
|
||||||
|
type="checkbox"
|
||||||
|
:id="JSON.stringify(modelValue)"
|
||||||
|
:name="groupName"
|
||||||
|
:aria-required="isRequired"
|
||||||
|
:value="value"
|
||||||
|
:checked="isChecked"
|
||||||
|
@change="handleSelectionChange"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
v-else
|
||||||
|
type="radio"
|
||||||
|
:id="JSON.stringify(modelValue)"
|
||||||
|
:name="groupName"
|
||||||
|
:aria-required="isRequired"
|
||||||
|
v-model="modelValue"
|
||||||
|
:checked="isChecked"
|
||||||
|
@change="handleSelectionChange"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import buttonMixin from "../mixins/button-mixin";
|
||||||
|
export default {
|
||||||
|
name: "test-button",
|
||||||
|
mixins: [buttonMixin],
|
||||||
|
};
|
||||||
|
</script>
|
||||||
56
src/layouts/test.vue
Normal file
56
src/layouts/test.vue
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
selectedMultiselectValues: {{ selectedMultiselectValues }}
|
||||||
|
|
||||||
|
<button-question
|
||||||
|
buttonType="testButton"
|
||||||
|
:answers="sampleAnswers"
|
||||||
|
:isMultiSelect="true"
|
||||||
|
groupName="multiselect-test"
|
||||||
|
v-model="selectedMultiselectValues"
|
||||||
|
></button-question>
|
||||||
|
|
||||||
|
<br /><br /><br />
|
||||||
|
selectedRadioValue: {{ selectedRadioValue }}
|
||||||
|
|
||||||
|
<button-question
|
||||||
|
buttonType="testButton"
|
||||||
|
:answers="sampleAnswers"
|
||||||
|
:isMultiSelect="false"
|
||||||
|
groupName="radio-test"
|
||||||
|
v-model="selectedRadioValue"
|
||||||
|
></button-question>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ButtonQuestion from "../common-components/button-question/button-question.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "test",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sampleAnswers: [
|
||||||
|
{
|
||||||
|
Text: "Part 1",
|
||||||
|
Value: "PART1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Text: "Part 2",
|
||||||
|
Value: "PART2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Text: "Part 3",
|
||||||
|
Value: "PART3",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
selectedMultiselectValues: [],
|
||||||
|
selectedRadioValue: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
// testButton,
|
||||||
|
ButtonQuestion,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
61
src/mixins/button-mixin.js
Normal file
61
src/mixins/button-mixin.js
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
export default {
|
||||||
|
model: {
|
||||||
|
prop: "modelValue",
|
||||||
|
event: "change",
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [Array, String, Number],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isMultiSelect: Boolean,
|
||||||
|
isWide: Boolean,
|
||||||
|
buttonImage: String,
|
||||||
|
buttonImageId: String,
|
||||||
|
buttonLabel: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isRequired: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
buttonLabelSubCopy: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
groupName: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {},
|
||||||
|
methods: {
|
||||||
|
handleSelectionChange(event) {
|
||||||
|
let isChecked = event.target.checked;
|
||||||
|
if (this.isMultiSelect && this.modelValue instanceof Array) {
|
||||||
|
let newValue = [...this.modelValue];
|
||||||
|
if (isChecked && !newValue.includes(this.value)) {
|
||||||
|
newValue.push(this.value);
|
||||||
|
} else {
|
||||||
|
newValue.splice(newValue.indexOf(this.value), 1);
|
||||||
|
}
|
||||||
|
this.$emit("change", newValue);
|
||||||
|
} else {
|
||||||
|
this.$emit("change", isChecked);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isChecked() {
|
||||||
|
if (this.isMultiSelect && this.modelValue instanceof Array) {
|
||||||
|
this.modelValue.includes(this.value);
|
||||||
|
}
|
||||||
|
return this.modelValue === this.value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -23,6 +23,7 @@ import { applicationConfig } from "../constants/application-config";
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import quote from "@/layouts/quote/quote.vue";
|
import quote from "@/layouts/quote/quote.vue";
|
||||||
|
import test from "@/layouts/test"
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
|
|
@ -30,6 +31,11 @@ const routes = [
|
||||||
name: "quote",
|
name: "quote",
|
||||||
component: quote,
|
component: quote,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/test", // This is a temporary route for testing.
|
||||||
|
name: "test",
|
||||||
|
component: test,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
name: "root",
|
name: "root",
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ export default {
|
||||||
buttonLabel: String, //Required: Label text
|
buttonLabel: String, //Required: Label text
|
||||||
isRequired: Boolean, //Required: is aria-required required or not?
|
isRequired: Boolean, //Required: is aria-required required or not?
|
||||||
altText: String, //Leave empty. Screen readers read the buttonLabel text. If alt has content, it will repeat unnecessarily.
|
altText: String, //Leave empty. Screen readers read the buttonLabel text. If alt has content, it will repeat unnecessarily.
|
||||||
buttonID: String, //Required: Unique
|
buttonID: String, // TODO KO We don't use this //Required: Unique
|
||||||
groupName: String, //Rquired: Unique
|
groupName: String, //Rquired: Unique
|
||||||
buttonLabelSubCopy: String, //Optional: sub text
|
buttonLabelSubCopy: String, //Optional: sub text
|
||||||
value: {
|
value: {
|
||||||
|
|
@ -84,7 +84,7 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
colLength: String,
|
// colLength: String,
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
selectedValues: [Array, String],
|
selectedValues: [Array, String],
|
||||||
hasError: Boolean,
|
hasError: Boolean,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue