Merge Develop branch, fix conflicts

This commit is contained in:
Adam Caouette 2022-02-17 12:24:41 -05:00
commit 51660aa968
26 changed files with 1240 additions and 1133 deletions

View file

@ -3,12 +3,14 @@ import buttonQuestion from "@/common-components/button-question/button-question"
import { nextTick } from "vue"; import { nextTick } from "vue";
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("Should show overflow classes on fieldset if isOverflowScrollable is true", async () => { it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => {
// Act // Act
const wrapper = shallowMount(buttonQuestion); const wrapper = shallowMount(buttonQuestion, {
await wrapper.setProps({ propsData: {
isOverflowScrollable: true, isOverflowScrollable: true,
}
}); });
// Assert // Assert
const fieldSet = wrapper.find('fieldset'); const fieldSet = wrapper.find('fieldset');
expect(fieldSet.classes()).toContain("overflow-scroll"); expect(fieldSet.classes()).toContain("overflow-scroll");
@ -16,11 +18,12 @@ describe("buttonQuestion.vue", () => {
}); });
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("Fieldset classes should contain row if button type is listCard", async () => { it("Fieldset classes should contain row if button type is listCard", () => {
// Act // Act
const wrapper = shallowMount(buttonQuestion); const wrapper = shallowMount(buttonQuestion, {
await wrapper.setProps({ propsData: {
buttonType: "listCard", buttonType: "listCard",
}
}); });
// Assert // Assert
const Div = wrapper.find('fieldset div'); const Div = wrapper.find('fieldset div');
@ -29,11 +32,12 @@ describe("buttonQuestion.vue", () => {
}); });
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("Fieldset classes should contain d-flex if button type is listButtonHorizontal", async () => { it("Fieldset classes should contain d-flex if button type is listButtonHorizontal", () => {
// Act // Act
const wrapper = shallowMount(buttonQuestion); const wrapper = shallowMount(buttonQuestion, {
await wrapper.setProps({ propsData: {
buttonType: "listButtonHorizontal", buttonType: "listButtonHorizontal",
}
}); });
// Assert // Assert
const Div = wrapper.find('fieldset div'); const Div = wrapper.find('fieldset div');
@ -57,12 +61,13 @@ describe("buttonQuestion.vue", () => {
}); });
describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => {
it("Should add values to array on checkbox click", async () => { it("Should add values to array on checkbox click", () => {
// Act // Act
const wrapper = shallowMount(buttonQuestion); const wrapper = shallowMount(buttonQuestion, {
await wrapper.setProps({ propsData: {
modelValue: ["2022", "2021", "2020"], modelValue: ["2022", "2021", "2020"],
isMultiSelect: true isMultiSelect: true,
}
}); });
const val = {isChecked: true, buttonId: "2019", } const val = {isChecked: true, buttonId: "2019", }
wrapper.vm.handleCheckedChanged(val); wrapper.vm.handleCheckedChanged(val);

View file

@ -19,17 +19,16 @@
:textPosition="textPosition" :textPosition="textPosition"
:isMultiSelect="isMultiSelect" :isMultiSelect="isMultiSelect"
:groupName="groupName" :groupName="groupName"
:loaderEnabled="loaderEnabled" :selectingInitiatesLoad="selectingInitiatesLoad"
:loaderColor="loaderColor" :loaderColor="loaderColor"
:loaderPosition="loaderPosition" :loaderPosition="loaderPosition"
:sizeInRem="sizeInRem"
:isWide="isWide" :isWide="isWide"
:isRequired="isRequired" :isRequired="isRequired"
:buttonImage="answer.AnswerImageUrl" :buttonImage="answer.AnswerImageUrl"
:buttonImageId="answer.ImageId" :buttonImageId="answer.ImageId"
:altText="answer.Name ? answer.Name : answer" :altText="answer.Name ? answer.Name : answer"
screenReaderOnlyText="(opens new window)" screenReaderOnlyText="(opens new window)"
:colLength="this.answers.length < 3 ? '' : '-4'" :colLength="getColLength"
:selectedButtonIDs="selectedValues" :selectedButtonIDs="selectedValues"
data-test="button" data-test="button"
:validationRules="validationRules" :validationRules="validationRules"
@ -37,7 +36,7 @@
</div> </div>
</fieldset> </fieldset>
</div> </div>
<div class="row px-3 my-6 form-test-error" v-if="!suppressError"> <div class="row mt-2 form-test-error" v-if="!suppressError">
<error-message :name="groupName"></error-message> <error-message :name="groupName"></error-message>
</div> </div>
</div> </div>
@ -65,7 +64,7 @@ export default {
type: String, type: String,
default: "text-center", default: "text-center",
}, },
loaderEnabled: Boolean, selectingInitiatesLoad: Boolean,
loaderColor: { loaderColor: {
type: String, type: String,
default: "blue", default: "blue",
@ -74,17 +73,11 @@ export default {
type: String, type: String,
default: "right", default: "right",
}, },
sizeInRem: {
type: [String, Number],
default: 1.5,
},
isRequired: Boolean, isRequired: Boolean,
isOverflowScrollable: Boolean, isOverflowScrollable: Boolean,
isWide: Boolean, isWide: Boolean,
modelValue: Array, modelValue: Array,
validationRules: String, validationRules: String,
name: String,
value: String,
suppressError: Boolean, suppressError: Boolean,
}, },
computed: { computed: {
@ -111,6 +104,13 @@ export default {
} }
return classes; return classes;
}, },
getColLength(){
if(this.isWide) {
return "12"
} else {
return this.answers.length < 3 ? '' : '-4';
}
},
selectedValues: { selectedValues: {
get: function() { get: function() {
return this.modelValue; return this.modelValue;
@ -120,18 +120,7 @@ export default {
} }
}, },
}, },
mounted(){
// UPDATE SELECTEDVALUES IF ONLY ONE ANSWER
if(Array.isArray(this.answers) && this.answers.length === 1) {
const newSelectedValues = this.selectedValues;
newSelectedValues.push(typeof(this.answers[0]) === 'object' ? this.answers[0].Name : this.answers[0]);
this.selectedValues = newSelectedValues;
}
},
methods: { methods: {
chooseAnswer(answer) {
this.$emit("update:modelValue", answer);
},
handleCheckedChanged(val) { handleCheckedChanged(val) {
if(this.isMultiSelect) { if(this.isMultiSelect) {
// Add or remove item to array of data to emit // Add or remove item to array of data to emit
@ -139,7 +128,7 @@ export default {
val.isChecked ? newSelectedValues.push(val.buttonId) : newSelectedValues.splice(newSelectedValues.indexOf(val.buttonId), 1); val.isChecked ? newSelectedValues.push(val.buttonId) : newSelectedValues.splice(newSelectedValues.indexOf(val.buttonId), 1);
this.selectedValues = newSelectedValues; this.selectedValues = newSelectedValues;
} else { } else {
this.selectedValues = [val.buttonId] this.selectedValues = [val.buttonId];
} }
}, },
}, },

View file

@ -21,7 +21,6 @@
isPrimary isPrimary
:buttonText="buttonText" :buttonText="buttonText"
loaderColor="white" loaderColor="white"
sizeInRem="1"
:class="isDisabled && 'form-test-invalid'" :class="isDisabled && 'form-test-invalid'"
:aria-disabled="isDisabled" :aria-disabled="isDisabled"
:isDisabled="isDisabled" :isDisabled="isDisabled"
@ -97,6 +96,10 @@ export default {
.btn-primary { .btn-primary {
width: 100%; width: 100%;
} }
a {
display: flex;
justify-content: center;
}
@media only screen and (min-width: 340px) { @media only screen and (min-width: 340px) {
.button-col, .button-col,
.link-col { .link-col {
@ -105,6 +108,10 @@ export default {
.btn-primary { .btn-primary {
width: auto; width: auto;
} }
a {
display: flex;
justify-content: flex-start;
}
} }
} }
</style> </style>

View file

@ -57,7 +57,7 @@ export default {
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
h5 { h5 {
line-height: 32px; line-height: 32px;

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@
:suppressError="errors.windshieldDamageTypeQuestion && errors.windshieldDamageTypeQuestion.startsWith('checkForRepairAndReplace')" :suppressError="errors.windshieldDamageTypeQuestion && errors.windshieldDamageTypeQuestion.startsWith('checkForRepairAndReplace')"
/> />
<alert <alert
class="my-3"
v-if="errors.windshieldDamageTypeQuestion && errors.windshieldDamageTypeQuestion.startsWith('checkForRepairAndReplace')" v-if="errors.windshieldDamageTypeQuestion && errors.windshieldDamageTypeQuestion.startsWith('checkForRepairAndReplace')"
alertClass="alert-danger" alertClass="alert-danger"
alertHeadline="You'll need to schedule separate appointments" alertHeadline="You'll need to schedule separate appointments"

View file

@ -1,7 +1,6 @@
<template> <template>
<div class="damage-location-question"> <div class="damage-location-question">
<buttonQuestion <buttonQuestion
v-if="answersToDisplay.length > 1"
:questionText="questionText" :questionText="questionText"
isMultiSelect isMultiSelect
:answers="answersToDisplay" :answers="answersToDisplay"

View file

@ -24,7 +24,7 @@ describe("replace-options-question.vue", () => {
test("Answers to display filtered by data from api.", async () => { test("Answers to display filtered by data from api.", async () => {
//Arrange //Arrange
const { wrapper, cmsContent, replaceOptions } = setupMocks({ dataFromStoreApi: ["Windshield", "FrontDoor"]}); const { wrapper, cmsContent, replaceOptions } = setupMocks({ dataFromStoreApi: ["Windshield", "FrontDoor"], filterByVehicleCategory: true});
//Act //Act
replaceOptionsQuestion.methods.initializeComponent.call(wrapper.vm, cmsContent, replaceOptions, "car-group"); replaceOptionsQuestion.methods.initializeComponent.call(wrapper.vm, cmsContent, replaceOptions, "car-group");

View file

@ -1,8 +1,9 @@
<template> <template>
<transition name="fade"> <transition name="fade">
<div class="replace-options-question"> <div class="replace-options-question" :class="this.answersToDisplay.length < 2 ? 'd-noneXXX' : ''">
<buttonQuestion <buttonQuestion
v-if="isAvailable && answersToDisplay.length > 0" v-if="isAvailable && answersToDisplay.length > 0"
isWide
:questionText="questionText" :questionText="questionText"
:isMultiSelect="isMultiSelect" :isMultiSelect="isMultiSelect"
:answers="answersToDisplay" :answers="answersToDisplay"
@ -70,6 +71,14 @@ export default ({
: []; : [];
}, },
}, },
mounted(){
// UPDATE SELECTEDVALUES IF ONLY ONE ANSWER
if(Array.isArray(this.answersToDisplay) && this.answersToDisplay.length === 1) {
const newSelectedValues = this.selectedValues;
newSelectedValues.push(this.answersToDisplay[0].Name);
this.selectedValues = newSelectedValues;
}
},
components: { components: {
buttonQuestion, buttonQuestion,
} }

View file

@ -175,7 +175,10 @@ function setupMocks({
return Promise.resolve({ return Promise.resolve({
driverSideOptions: { driverSideOptions: {
availableReplacementOptions: ["Front", "Back", "Side"], availableReplacementOptions: ["Front", "Back", "Side"],
} },
windshieldOptions: {
availableReplacementOptions: ["Front", "Back", "Side"],
},
}); });
}); });
const apiResponses = { const apiResponses = {
@ -193,6 +196,9 @@ function setupMocks({
damageOptions: { damageOptions: {
driverSideOptions: { driverSideOptions: {
availableReplacementOptions: ["Front", "Back", "Side"], availableReplacementOptions: ["Front", "Back", "Side"],
},
windshieldOptions: {
availableReplacementOptions: ["Front", "Back", "Side"],
} }
}, },
}; };
@ -220,6 +226,11 @@ function setupMocks({
initializeComponent: jest.fn(), initializeComponent: jest.fn(),
}; };
const windshieldOptions = replaceOptionsQuestion
windshieldOptions.methods = {
initializeComponent: jest.fn(),
};
damageLocationQuestion.methods = { damageLocationQuestion.methods = {
initializeComponent: jest.fn(), initializeComponent: jest.fn(),
}; };
@ -245,12 +256,18 @@ function setupMocks({
funnelSubHeaderWrapper.vm.initializeComponent = funnelSubHeaderWrapper.vm.initializeComponent =
funnelSubHeader.methods.initializeComponent; funnelSubHeader.methods.initializeComponent;
const driverSideOptionsWrapper = wrapper.findComponent({ const driverSideOptionsWrapper = wrapper.findAllComponents({
name: "replaceOptionsQuestion", name: "replaceOptionsQuestion",
}); }).at(0);
driverSideOptionsWrapper.vm.initializeComponent = driverSideOptionsWrapper.vm.initializeComponent =
replaceOptionsQuestion.methods.initializeComponent; replaceOptionsQuestion.methods.initializeComponent;
const windshieldOptionsWrapper = wrapper.findAllComponents({
name: "replaceOptionsQuestion",
}).at(1);
windshieldOptionsWrapper.vm.initializeComponent =
replaceOptionsQuestion.methods.initializeComponent;
const damageLocationQuestionWrapper = wrapper.findComponent({ const damageLocationQuestionWrapper = wrapper.findComponent({
name: "damageLocationQuestion", name: "damageLocationQuestion",
}); });

View file

@ -8,10 +8,15 @@
v-model="selectedDamageLocations" v-model="selectedDamageLocations"
groupName="DamageLocationQuestion" groupName="DamageLocationQuestion"
/> />
<replaceOptionsQuestion
ref="windshieldOptions"
isAvailable
groupName="windshieldOptions"
v-model="windshieldOptionsData"
/>
<replaceOptionsQuestion <replaceOptionsQuestion
ref="driverSideOptions" ref="driverSideOptions"
isAvailable isAvailable
isMultiSelect
filterByVehicleCategory filterByVehicleCategory
v-model="driverSideOptionsData" v-model="driverSideOptionsData"
groupName="DriverSideReplaceOptionsQuestion" groupName="DriverSideReplaceOptionsQuestion"
@ -88,6 +93,9 @@ export default {
vm.$refs.backGlassOptions.initializeComponent( vm.$refs.backGlassOptions.initializeComponent(
resultMap.cmsContent.RearReplaceOptionsQuestion, resultMap.damageOptions.backGlassOptions.availableReplacementOptions resultMap.cmsContent.RearReplaceOptionsQuestion, resultMap.damageOptions.backGlassOptions.availableReplacementOptions
); );
vm.$refs.windshieldOptions.initializeComponent(
resultMap.cmsContent.WindshieldReplaceOptionsQuestion, resultMap.damageOptions.windshieldOptions.availableReplacementOptions
);
vm.$refs.funnelFooter.initializeComponent( vm.$refs.funnelFooter.initializeComponent(
resultMap.cmsContent.FunnelFooterWidget resultMap.cmsContent.FunnelFooterWidget
); );
@ -98,6 +106,7 @@ export default {
selectedDamageLocations: [], selectedDamageLocations: [],
driverSideOptionsData: [], driverSideOptionsData: [],
selectedRearReplaceOptions: [], selectedRearReplaceOptions: [],
windshieldOptionsData: [],
} }
}, },
methods: { methods: {

View file

@ -2,11 +2,11 @@
<buttonQuestion <buttonQuestion
class="radioQuestion" class="radioQuestion"
isOverflowScrollable isOverflowScrollable
selectingInitiatesLoad
:questionText="questionText" :questionText="questionText"
:answers="makes" :answers="makes"
groupName="Choose Vehicle Make" groupName="Choose Vehicle Make"
textPosition="text-start" textPosition="text-start"
:loaderEnabled="true"
v-model="selectedValueAsArray" v-model="selectedValueAsArray"
isRequired=true isRequired=true
/> />

View file

@ -2,11 +2,11 @@
<buttonQuestion <buttonQuestion
class="radioQuestion" class="radioQuestion"
isOverflowScrollable isOverflowScrollable
selectingInitiatesLoad
:questionText="questionText" :questionText="questionText"
:answers="models" :answers="models"
groupName="Choose Vehicle Model" groupName="Choose Vehicle Model"
textPosition="text-start" textPosition="text-start"
:loaderEnabled="true"
v-model="selectedValueAsArray" v-model="selectedValueAsArray"
isRequired=true isRequired=true
/> />

View file

@ -2,11 +2,11 @@
<buttonQuestion <buttonQuestion
class="radioQuestion" class="radioQuestion"
isOverflowScrollable isOverflowScrollable
selectingInitiatesLoad
:questionText="questionText" :questionText="questionText"
:answers="styles" :answers="styles"
groupName="Choose Vehicle Style" groupName="Choose Vehicle Style"
textPosition="text-start" textPosition="text-start"
:loaderEnabled="true"
v-model="selectedValueAsArray" v-model="selectedValueAsArray"
isRequired=true isRequired=true
/> />

View file

@ -2,11 +2,11 @@
<buttonQuestion <buttonQuestion
class="radioQuestion" class="radioQuestion"
isOverflowScrollable isOverflowScrollable
selectingInitiatesLoad
:questionText="questionText" :questionText="questionText"
:answers="years" :answers="years"
groupName="Choose Vehicle Year" groupName="Choose Vehicle Year"
textPosition="text-start" textPosition="text-start"
:loaderEnabled="true"
v-model="selectedValueAsArray" v-model="selectedValueAsArray"
isRequired=true isRequired=true
/> />

View file

@ -1,24 +1,49 @@
.has-error { .has-error {
&.list-button, &.list-button,
&.list-card, &.list-card {
border: 1px solid transparent;
color: $red;
label {
border: 1px solid $red;
border-radius: .5rem;
}
}
input[type=checkbox]:focus + label,
input[type=radio]:focus + label,
input[type=checkbox]:checked + label,
input[type=radio]:checked + label {
box-shadow: 0 0 0 2.5px transparent !important;
}
&.list-button-horizontal { &.list-button-horizontal {
color: $red; color: $red;
label { label {
border: 1px solid $red; border: 1px solid $red;
} }
} }
&.ui-radio,
&.ui-checkbox {
input[type=radio]+label:before,
input[type=checkbox]+label:before {
border: 1px solid $red;
}
input[type=checkbox]:checked + label:before {
border: 1px solid $blue;
}
}
} }
.form-test-error { .form-test-error {
color: $red; color: $red;
font-weight: bold; font-size: .875rem;
font-weight: 500;
} }
.form-test-invalid { .form-test-invalid {
&.btn.btn-primary { &.btn.btn-primary {
color: $gray; color: $gray;
background: $gray-200; background: $gray-200;
cursor: default; cursor: pointer;
pointer-events: all;
} }
&.btn.btn-primary:hover, &.btn.btn-primary:hover,
&.btn.btn-primary:focus, &.btn.btn-primary:focus,

View file

@ -76,26 +76,4 @@ describe("buttonMain.vue", () => {
expect(loader.attributes("class")).toContain("right"); expect(loader.attributes("class")).toContain("right");
}); });
it("Should return loader size in rem", async () => {
// Act
const wrapper = shallowMount(buttonMain, {
propsData: {
sizeInRem: 1,
loaderEnabled: true,
},
});
// Assert
const label = wrapper.find("label");
wrapper.vm.clicked();
await nextTick();
const loader = wrapper.find("loader-stub");
expect(loader.attributes("style")).toContain("1rem");
});
}); });

View file

@ -1,15 +1,14 @@
<template> <template>
<button <button
:aria-disabled="isDisabled" :aria-disabled="isDisabled"
class="btn d-flex align-items-center py-3 px-2" class="btn d-flex align-items-center py-3 px-4 delay"
:class="[isPrimary ? 'btn-primary' : 'btn-secondary',isFloat ? 'float-end' : '']" :class="[isPrimary ? 'btn-primary' : 'btn-secondary',isFloat ? 'float-end' : '', isLoaderDisplayed ? 'has-loader' : '']"
@click="clicked()" @click="clicked()"
> >
<span class="m-0">{{ this.buttonText }}</span> <span class="m-0">{{ this.buttonText }}</span>
<loader <loader
class="ms-2" class="ms-2"
v-if="isLoaderDisplayed" v-if="isLoaderDisplayed"
v-bind:style="{ width: `${sizeInRem}rem`, height: `${sizeInRem}rem` }"
v-bind:class="[this.loaderColor, this.loaderPosition]" v-bind:class="[this.loaderColor, this.loaderPosition]"
/> />
</button> </button>
@ -25,7 +24,6 @@ export default {
isDisabled: Boolean, isDisabled: Boolean,
loaderColor: String, loaderColor: String,
loaderPosition: String, loaderPosition: String,
sizeInRem: [Number, String],
isFloat: Boolean, isFloat: Boolean,
}, },
data() { data() {
@ -51,13 +49,12 @@ export default {
.btn { .btn {
&.btn-primary { &.btn-primary {
position: relative; position: relative;
background: $blue-700; background: linear-gradient(270deg, $blue-500 0%, $blue-700 100%);
@include blue-gradient;
border: none; border: none;
border-radius: $border-radius-lg; border-radius: $border-radius-lg;
color: $white; color: $white;
transition: all 150ms linear;
justify-content: center; justify-content: center;
font-weight: 500;
&:hover { &:hover {
background: linear-gradient( background: linear-gradient(
270deg, 270deg,
@ -71,19 +68,33 @@ export default {
outline: none; outline: none;
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700; box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
color: $white; color: $white;
@include blue-gradient;
}
&:disabled {
background: $gray-100 !important;
background: linear-gradient( background: linear-gradient(
270deg, 270deg,
$gray-100 0%, rgba(6, 87, 124, 1) 0%,
$gray-100 100% rgba(6, 87, 124, 1) 100%
);
}
&:disabled {
background: $gray-200 !important;
background: linear-gradient(
270deg,
$gray-200 0%,
$gray-200 100%
) !important; ) !important;
color: $gray !important; color: $gray-600 !important;
font-weight: 400;
height: 48px; height: 48px;
border: none; border: none;
border-radius: $border-radius-lg; border-radius: $border-radius-lg;
cursor: pointer;
pointer-events: all;
}
&.has-loader {
color: $white;
background: $blue-700;
}
&.delay {// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
} }
} }
&.btn-secondary { &.btn-secondary {
@ -92,6 +103,7 @@ export default {
border: 1px solid $blue; border: 1px solid $blue;
border-radius: $border-radius-lg; border-radius: $border-radius-lg;
color: $blue; color: $blue;
font-weight: 500;
transition: all 150ms linear; transition: all 150ms linear;
&:hover { &:hover {
color: $white; color: $white;
@ -107,10 +119,20 @@ export default {
} }
&:disabled { &:disabled {
background: transparent; background: transparent;
color: $gray !important; color: $gray-550 !important;
font-weight: 400;
height: 48px; height: 48px;
border: 1px solid $gray-300; border: 1px solid $gray-550;
border-radius: $border-radius-lg; border-radius: $border-radius-lg;
cursor: pointer;
pointer-events: all;
}
&.has-loader {
color: $white;
@include blue-gradient;
}
&.delay {// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
} }
} }
} }

View file

@ -1,6 +1,6 @@
<template> <template>
<!-- Checkbox groups MUST be wrapped in a <fieldset> and <legend> tag --> <!-- Checkbox groups MUST be wrapped in a <fieldset> and <legend> tag -->
<div class="ui-checkbox d-flex"> <div class="ui-checkbox d-flex" :class="[hasError ? 'has-error' : '']">
<input <input
type="checkbox" type="checkbox"
aria-checked="false" aria-checked="false"
@ -28,6 +28,7 @@ export default {
checkboxLabel: String, checkboxLabel: String,
screenReaderOnlyText: String, screenReaderOnlyText: String,
isRequired: Boolean, isRequired: Boolean,
hasError: Boolean
}, },
}; };
</script> </script>

View file

@ -91,7 +91,7 @@ describe("list-button-horizontal.vue", () => {
// Act // Act
const wrapper = shallowMount(listButtonHorizontal, { const wrapper = shallowMount(listButtonHorizontal, {
propsData: { propsData: {
loaderEnabled: true, selectingInitiatesLoad: true,
}, },
}); });
@ -99,6 +99,7 @@ describe("list-button-horizontal.vue", () => {
const label = wrapper.find("label"); const label = wrapper.find("label");
wrapper.vm.handleCheckChange = jest.fn();
wrapper.vm.handleClick(); wrapper.vm.handleClick();
await nextTick(); await nextTick();
@ -113,7 +114,7 @@ describe("list-button-horizontal.vue", () => {
const wrapper = shallowMount(listButtonHorizontal, { const wrapper = shallowMount(listButtonHorizontal, {
propsData: { propsData: {
loaderColor: "blue", loaderColor: "blue",
loaderEnabled: true, selectingInitiatesLoad: true,
}, },
}); });
@ -121,6 +122,7 @@ describe("list-button-horizontal.vue", () => {
const label = wrapper.find("label"); const label = wrapper.find("label");
wrapper.vm.handleCheckChange = jest.fn();
wrapper.vm.handleClick(); wrapper.vm.handleClick();
await nextTick(); await nextTick();
@ -135,7 +137,7 @@ describe("list-button-horizontal.vue", () => {
const wrapper = shallowMount(listButtonHorizontal, { const wrapper = shallowMount(listButtonHorizontal, {
propsData: { propsData: {
loaderPosition: "right", loaderPosition: "right",
loaderEnabled: true, selectingInitiatesLoad: true,
}, },
}); });
@ -143,6 +145,7 @@ describe("list-button-horizontal.vue", () => {
const label = wrapper.find("label"); const label = wrapper.find("label");
wrapper.vm.handleCheckChange = jest.fn();
wrapper.vm.handleClick(); wrapper.vm.handleClick();
await nextTick(); await nextTick();
@ -152,28 +155,6 @@ describe("list-button-horizontal.vue", () => {
expect(loader.attributes("class")).toContain("right"); expect(loader.attributes("class")).toContain("right");
}); });
it("Should return loader size in rem", async () => {
// Act
const wrapper = shallowMount(listButtonHorizontal, {
propsData: {
sizeInRem: 1,
loaderEnabled: true,
},
});
// Assert
const label = wrapper.find("label");
wrapper.vm.handleClick();
await nextTick();
const loader = wrapper.find("loader-stub");
expect(loader.attributes("style")).toContain("1rem");
});
it("Should emit button value on click", async () => { it("Should emit button value on click", async () => {
// Act // Act
const wrapper = shallowMount(listButtonHorizontal, { const wrapper = shallowMount(listButtonHorizontal, {

View file

@ -1,6 +1,7 @@
<template> <template>
<div <div
class="list-group list-button-horizontal d-flex flex-column w-100 mb-2" class="list-group list-button-horizontal d-flex flex-column w-100 mb-2"
:class="hasError ? 'has-error' : ''"
@mouseup="handleClick(value)" @mouseup="handleClick(value)"
@keyup.space="handleClick(value)" @keyup.space="handleClick(value)"
> >
@ -12,7 +13,7 @@
:aria-required="isRequired" :aria-required="isRequired"
:data-focus-target="groupName" :data-focus-target="groupName"
v-model="checkValue" v-model="checkValue"
@change="handleCheckChange" @change="!selectingInitiatesLoad ? handleCheckChange : ''"
/> />
<label <label
tabindex="-1" tabindex="-1"
@ -38,7 +39,6 @@
</span> </span>
<loader <loader
v-if="isLoaderDisplayed && !isMultiSelect" v-if="isLoaderDisplayed && !isMultiSelect"
:style="{width: `${sizeInRem}rem`, height: `${sizeInRem}rem`}"
:class="[loaderColor, loaderPosition]" :class="[loaderColor, loaderPosition]"
/> />
</label> </label>
@ -60,10 +60,9 @@ export default {
buttonLabelSubCopy: String, buttonLabelSubCopy: String,
screenReaderOnlyText: String, screenReaderOnlyText: String,
textPosition: String, textPosition: String,
loaderEnabled: Boolean, selectingInitiatesLoad: Boolean,
loaderColor: String, loaderColor: String,
loaderPosition: String, loaderPosition: String,
sizeInRem: [Number, String],
isRequired: Boolean, isRequired: Boolean,
value: { value: {
// Field initial value // Field initial value
@ -71,6 +70,7 @@ export default {
default: "", default: "",
}, },
selectedButtonIDs: [Array, String], selectedButtonIDs: [Array, String],
hasError: Boolean,
}, },
data() { data() {
return { return {
@ -88,8 +88,9 @@ export default {
this.isLoaderDisplayed = true; this.isLoaderDisplayed = true;
}, },
handleClick(value) { handleClick(value) {
if (this.loaderEnabled) { if(this.selectingInitiatesLoad) {
this.displayLoader(); this.displayLoader();
this.handleCheckChange();
} }
this.handleChange(value); this.handleChange(value);
}, },
@ -139,6 +140,7 @@ export default {
&:checked + label { &:checked + label {
background: $blue-100; background: $blue-100;
box-shadow: 0 0 0 1px $blue; box-shadow: 0 0 0 1px $blue;
z-index: 2;
} }
&:checked + label p:first-child { &:checked + label p:first-child {
font-weight: 500; font-weight: 500;
@ -155,7 +157,7 @@ export default {
&:hover { &:hover {
box-shadow: 0 0 0 4px $blue-300; box-shadow: 0 0 0 4px $blue-300;
cursor: pointer; cursor: pointer;
z-index: 2; z-index: 3 !important;
} }
+ p { + p {
display: none; display: none;
@ -165,6 +167,7 @@ export default {
label { label {
border-bottom-left-radius: 0.5rem; border-bottom-left-radius: 0.5rem;
border-top-left-radius: 0.5rem; border-top-left-radius: 0.5rem;
z-index: 2;
} }
} }
&:last-of-type { &:last-of-type {

View file

@ -91,7 +91,7 @@ describe("list-button.vue", () => {
// Act // Act
const wrapper = shallowMount(listButton, { const wrapper = shallowMount(listButton, {
propsData: { propsData: {
loaderEnabled: true, selectingInitiatesLoad: true,
}, },
}); });
@ -99,6 +99,7 @@ describe("list-button.vue", () => {
const label = wrapper.find("label"); const label = wrapper.find("label");
wrapper.vm.handleCheckChange = jest.fn();
wrapper.vm.handleClick(); wrapper.vm.handleClick();
await nextTick(); await nextTick();
@ -113,16 +114,15 @@ describe("list-button.vue", () => {
const wrapper = shallowMount(listButton, { const wrapper = shallowMount(listButton, {
propsData: { propsData: {
loaderColor: "blue", loaderColor: "blue",
loaderEnabled: true, selectingInitiatesLoad: true,
}, },
}); });
// Assert // Assert
const label = wrapper.find("label"); const label = wrapper.find("label");
wrapper.vm.handleCheckChange = jest.fn();
wrapper.vm.handleClick(); wrapper.vm.handleClick();
await nextTick(); await nextTick();
const loader = wrapper.find("loader-stub"); const loader = wrapper.find("loader-stub");
@ -135,7 +135,7 @@ describe("list-button.vue", () => {
const wrapper = shallowMount(listButton, { const wrapper = shallowMount(listButton, {
propsData: { propsData: {
loaderPosition: "right", loaderPosition: "right",
loaderEnabled: true, selectingInitiatesLoad: true,
}, },
}); });
@ -143,6 +143,7 @@ describe("list-button.vue", () => {
const label = wrapper.find("label"); const label = wrapper.find("label");
wrapper.vm.handleCheckChange = jest.fn();
wrapper.vm.handleClick(); wrapper.vm.handleClick();
await nextTick(); await nextTick();
@ -152,28 +153,6 @@ describe("list-button.vue", () => {
expect(loader.attributes("class")).toContain("right"); expect(loader.attributes("class")).toContain("right");
}); });
it("Should return loader size in rem", async () => {
// Act
const wrapper = shallowMount(listButton, {
propsData: {
sizeInRem: 1,
loaderEnabled: true,
},
});
// Assert
const label = wrapper.find("label");
wrapper.vm.handleClick();
await nextTick();
const loader = wrapper.find("loader-stub");
expect(loader.attributes("style")).toContain("1rem");
});
it("Should emit button value on click", async () => { it("Should emit button value on click", async () => {
// Act // Act
const wrapper = shallowMount(listButton, { const wrapper = shallowMount(listButton, {

View file

@ -1,6 +1,7 @@
<template> <template>
<div <div
class="list-group list-button d-flex flex-column w-100 mb-2" class="list-group list-button d-flex flex-column w-100 mb-2"
:class="hasError ? 'has-error' : ''"
@mouseup="handleClick(value)" @mouseup="handleClick(value)"
@keyup.space="handleClick(value)" @keyup.space="handleClick(value)"
> >
@ -12,7 +13,7 @@
:aria-required="isRequired" :aria-required="isRequired"
:data-focus-target="groupName" :data-focus-target="groupName"
v-model="checkValue" v-model="checkValue"
@change="handleCheckChange" @change="!selectingInitiatesLoad ? handleCheckChange : ''"
> >
<label <label
tabindex="-1" tabindex="-1"
@ -41,7 +42,6 @@
</span> </span>
<loader <loader
v-if="isLoaderDisplayed && !isMultiSelect" v-if="isLoaderDisplayed && !isMultiSelect"
:style="{ width: `${sizeInRem}rem`, height: `${sizeInRem}rem` }"
:class="[this.loaderColor, this.loaderPosition]" :class="[this.loaderColor, this.loaderPosition]"
/> />
</label> </label>
@ -63,16 +63,16 @@ export default {
textPosition: String, textPosition: String,
buttonLabelSubCopy: String, buttonLabelSubCopy: String,
screenReaderOnlyText: String, screenReaderOnlyText: String,
loaderEnabled: Boolean, selectingInitiatesLoad: Boolean,
loaderColor: String, loaderColor: String,
loaderPosition: String, loaderPosition: String,
sizeInRem: [Number,String],
value: { value: {
// Field initial value // Field initial value
type: [String, Number], type: [String, Number],
default: "", default: "",
}, },
selectedButtonIDs: [Array, String], selectedButtonIDs: [Array, String],
hasError: Boolean,
}, },
data() { data() {
return { return {
@ -90,8 +90,9 @@ export default {
this.isLoaderDisplayed = true; this.isLoaderDisplayed = true;
}, },
handleClick(value) { handleClick(value) {
if (this.loaderEnabled) { if(this.selectingInitiatesLoad) {
this.displayLoader(); this.displayLoader();
this.handleCheckChange();
} }
this.handleChange(value); this.handleChange(value);
}, },
@ -100,7 +101,7 @@ export default {
if (!isInitialization) { if (!isInitialization) {
this.$emit('isCheckedChanged', { isChecked: this.checkValue, buttonId: this.buttonID.toString() }); this.$emit('isCheckedChanged', { isChecked: this.checkValue, buttonId: this.buttonID.toString() });
} }
} },
}, },
components: { components: {
loader, loader,

View file

@ -2,7 +2,7 @@
<div :class="'col' + colLength"> <div :class="'col' + colLength">
<div <div
class="list-card w-100 rounded-3 d-flex align-items-center h-100" class="list-card w-100 rounded-3 d-flex align-items-center h-100"
:class="[isWide ? 'horizontal' : '', errors.length > 0 ? 'has-error' : '']" :class="[isWide ? 'horizontal' : '', errors.length > 0 ? 'has-error' : '', hasError ? 'has-error' : '']"
> >
<input <input
:type="isMultiSelect ? 'checkbox' : 'radio'" :type="isMultiSelect ? 'checkbox' : 'radio'"
@ -53,10 +53,8 @@ import { useField } from "vee-validate";
export default { export default {
name: "listCard", name: "listCard",
props: { props: {
//Must choose one of the following four options
isMultiSelect: Boolean, //Defines use as checkbox isMultiSelect: Boolean, //Defines use as checkbox
isWide: Boolean, isWide: Boolean,
//end must choose
buttonImage: String, //Required: File name of image buttonImage: String, //Required: File name of image
buttonImageId: String, buttonImageId: String,
buttonLabel: String, //Required: Label text buttonLabel: String, //Required: Label text
@ -73,6 +71,7 @@ export default {
colLength: String, colLength: String,
validationRules: String, validationRules: String,
selectedButtonIDs: [Array, String], selectedButtonIDs: [Array, String],
hasError: Boolean,
}, },
computed: { computed: {
getLabelClasses() { getLabelClasses() {
@ -151,6 +150,7 @@ export default {
cursor: pointer; cursor: pointer;
} }
p { p {
color: $gray-600;
text-align: center; text-align: center;
&.sub-copy { &.sub-copy {
color: $gray-550; color: $gray-550;
@ -166,6 +166,14 @@ export default {
box-shadow: 0 0 0 1px $blue; box-shadow: 0 0 0 1px $blue;
border-radius: 0.5rem; border-radius: 0.5rem;
} }
&:checked + label {
p {
color: $black;
}
.sub-copy {
color: $gray-600;
}
}
+ label::before { + label::before {
content: ""; content: "";
position: absolute; position: absolute;

View file

@ -3,7 +3,6 @@
class="loader" class="loader"
role="alert" role="alert"
aria-label="Loading new page" aria-label="Loading new page"
v-bind:style="{ width: `${sizeInRem}rem`, height: `${sizeInRem}rem` }"
v-bind:class="[this.loaderColor, this.loaderPosition]" v-bind:class="[this.loaderColor, this.loaderPosition]"
></div> ></div>
</template> </template>
@ -13,10 +12,6 @@ export default {
name: "loader", name: "loader",
/* Specify size in number value which translates to rem value. For example, 1.5 = 1.5rem = 24px */ /* Specify size in number value which translates to rem value. For example, 1.5 = 1.5rem = 24px */
props: { props: {
sizeInRem: {
type: Number,
default: 1,
},
/* Color options: red, green, blue, white, black */ /* Color options: red, green, blue, white, black */
loaderColor: { loaderColor: {
type: String, type: String,
@ -50,8 +45,8 @@ export default {
mask: url(../../assets/img/icons/spinner.svg); mask: url(../../assets/img/icons/spinner.svg);
mask-size: cover; mask-size: cover;
position: relative; position: relative;
width: 100%; width: 1rem;
height: 100%; height: 1rem;
animation: rotation 1s infinite linear; animation: rotation 1s infinite linear;
@keyframes rotation { @keyframes rotation {
100% { 100% {

View file

@ -1,6 +1,6 @@
<template> <template>
<!-- Checkbox groups MUST be wrapped in a <fieldset> and <legend> tag and must contain tabindex --> <!-- Checkbox groups MUST be wrapped in a <fieldset> and <legend> tag and must contain tabindex -->
<div class="ui-radio d-flex"> <div class="ui-radio d-flex" :class="[hasError ? 'has-error' : '']">
<input <input
type="radio" type="radio"
aria-checked="false" aria-checked="false"
@ -35,6 +35,7 @@ export default {
default: "", default: "",
}, },
screenReaderOnlyText: String, screenReaderOnlyText: String,
hasError: Boolean,
}, },
data() { data() {
return { return {