Merge branch 'develop' into feature/CSR-296
This commit is contained in:
commit
01f511915a
19 changed files with 525 additions and 251 deletions
|
|
@ -16,6 +16,7 @@ module.exports = {
|
|||
"!src/layouts/vehicle-damage/windshield-damage-type-question/windshield-damage-type-question.vue",
|
||||
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
|
||||
"!src/layouts/address-poc/address-poc.vue",
|
||||
"!src/layouts/nested-radio-poc/nested-radio.vue",
|
||||
], //! means exclude from coverage.
|
||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||
coverageThreshold: {
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
handleCheckedChanged(val) {
|
||||
if(this.isMultiSelect) {
|
||||
if(this.isMultiSelect && this.selectedValues) {
|
||||
// Add or remove item to array of data to emit
|
||||
const newSelectedValues = this.selectedValues;
|
||||
val.isChecked ? newSelectedValues.push(val.buttonId) : newSelectedValues.splice(newSelectedValues.indexOf(val.buttonId), 1);
|
||||
|
|
|
|||
75
src/layouts/nested-radio-poc/nested-radio.vue
Normal file
75
src/layouts/nested-radio-poc/nested-radio.vue
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
|
||||
<div class="container-fluid nested-radio">
|
||||
<div class="row mb-1">
|
||||
<div class="col">
|
||||
<listCard
|
||||
groupName="listcard1"
|
||||
isWide="true"
|
||||
buttonImage="https://digitalconsumercms-dev.safelite.com/images/default-source/damage-options/car.svg?sfvrsn=1468d7f1_3"
|
||||
buttonLabel="Green Tint, Blue Shade"
|
||||
buttonID="radio1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1">
|
||||
<div class="col">
|
||||
<p class="mb-0 fw-bold">Ok, select the features</p>
|
||||
<buttonQuestion
|
||||
buttonType="radio"
|
||||
groupName="Demo Group"
|
||||
buttonID="button1"
|
||||
isRequired
|
||||
value="test button"
|
||||
screenReaderOnlyText="rain sensor, solar, 3rd visor band"
|
||||
:answers="demoArray"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<listCard
|
||||
groupName="listcard1"
|
||||
isWide="true"
|
||||
buttonImage="https://digitalconsumercms-dev.safelite.com/images/default-source/damage-options/car.svg?sfvrsn=1468d7f1_3"
|
||||
buttonLabel="Green Tint"
|
||||
buttonID="radio2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
import listCard from "@/ux-components/list-card/list-card";
|
||||
|
||||
export default {
|
||||
name: "nestedRadio",
|
||||
components: {
|
||||
buttonQuestion,
|
||||
listCard,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
demoArray: [
|
||||
"rain sensor, solar, 3rd visor band",
|
||||
"rain sensor, heated glass, solar, 3rd visor band",
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.nested-radio {
|
||||
.ui-radio {
|
||||
flex-direction: column;
|
||||
margin: .25rem 0;
|
||||
}
|
||||
p {
|
||||
font-size: .875rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -53,7 +53,7 @@ export default ({
|
|||
},
|
||||
updateSelectedValues() {
|
||||
// UPDATE SELECTEDVALUES IF ONLY ONE ANSWER
|
||||
if(Array.isArray(this.answersToDisplay) && this.answersToDisplay.length === 1) {
|
||||
if(Array.isArray(this.answersToDisplay) && this.answersToDisplay.length === 1 && this.selectedValues) {
|
||||
const newSelectedValues = this.selectedValues;
|
||||
newSelectedValues.push(this.answersToDisplay[0].Name);
|
||||
console.log('YES, ONLY ONE, newSelectedValues: ', newSelectedValues)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
|||
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
|
||||
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
||||
import damageLocationQuestion from "@/layouts/vehicle-damage/damage-location-question/damage-location-question";
|
||||
import windshieldOptions from "@/layouts/vehicle-damage/windshield-options/windshield-options";
|
||||
|
||||
// Supporting Files
|
||||
import { settleAllPromises } from "@/helpers/layout-helper.js";
|
||||
|
|
@ -219,7 +220,6 @@ function setupMocks({
|
|||
}) {
|
||||
//Mock api responses
|
||||
baseMixin.methods.dispatchNonBlockingStoreAction = jest.fn();
|
||||
|
||||
const apiResponses = {
|
||||
cmsContent: {
|
||||
FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
|
||||
|
|
@ -237,7 +237,7 @@ function setupMocks({
|
|||
availableReplacementOptions: ["Front", "Back", "Side"],
|
||||
},
|
||||
windshieldOptions: {
|
||||
availableReplacementOptions: ["Front", "Back", "Side"],
|
||||
availableReplacementOptions: ["Single", "Driver", "Passenger"],
|
||||
},
|
||||
backGlassOptions: {
|
||||
availableReplacementOptions: ["Front", "Back", "Side"],
|
||||
|
|
@ -268,12 +268,11 @@ function setupMocks({
|
|||
initializeComponent: jest.fn(),
|
||||
};
|
||||
|
||||
const windshieldOptions = replaceOptionsQuestion
|
||||
windshieldOptions.methods = {
|
||||
damageLocationQuestion.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
};
|
||||
|
||||
damageLocationQuestion.methods = {
|
||||
windshieldOptions.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
};
|
||||
|
||||
|
|
@ -304,11 +303,13 @@ function setupMocks({
|
|||
driverSideOptionsWrapper.vm.initializeComponent =
|
||||
replaceOptionsQuestion.methods.initializeComponent;
|
||||
|
||||
const windshieldOptionsWrapper = wrapper.findAllComponents({
|
||||
name: "replaceOptionsQuestion",
|
||||
}).at(1);
|
||||
const windshieldOptionsWrapper = wrapper.findComponent({
|
||||
name: "windshieldOptions",
|
||||
});
|
||||
|
||||
windshieldOptionsWrapper.vm.initializeComponent =
|
||||
replaceOptionsQuestion.methods.initializeComponent;
|
||||
windshieldOptions.methods.initializeComponent;
|
||||
|
||||
|
||||
const backGlassOptionsWrapper = wrapper.findAllComponents({
|
||||
name: "replaceOptionsQuestion",
|
||||
|
|
|
|||
|
|
@ -8,12 +8,6 @@
|
|||
v-model="selectedDamageLocations"
|
||||
groupName="DamageLocationQuestion"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="windshieldOptions"
|
||||
isAvailable
|
||||
groupName="windshieldOptions"
|
||||
v-model="windshieldOptionsData"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="driverSideOptions"
|
||||
isAvailable
|
||||
|
|
@ -21,6 +15,17 @@
|
|||
v-model="driverSideOptionsData"
|
||||
groupName="DriverSideReplaceOptionsQuestion"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="windshieldOptions"
|
||||
isAvailable
|
||||
groupName="windshieldOptions"
|
||||
v-model="windshieldOptionsData"
|
||||
/>
|
||||
<windshieldOptions
|
||||
ref="windshieldOptions"
|
||||
v-model="selectedWindshieldOptions"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="backGlassOptions"
|
||||
:isAvailable="isRearWindowDamageLocation"
|
||||
|
|
@ -37,8 +42,9 @@ import funnelHeader from "@/common-components/funnel-header/funnel-header";
|
|||
import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
|
||||
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
|
||||
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
|
||||
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
||||
import damageLocationQuestion from "@/layouts/vehicle-damage/damage-location-question/damage-location-question";
|
||||
import replaceOptionsQuestion from"@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
||||
import damageLocationQuestion from"@/layouts/vehicle-damage/damage-location-question/damage-location-question";
|
||||
import windshieldOptions from "@/layouts/vehicle-damage/windshield-options/windshield-options";
|
||||
|
||||
// Supporting files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
|
|
@ -94,6 +100,7 @@ export default {
|
|||
resultMap.cmsContent.RearReplaceOptionsQuestion, resultMap.damageOptions.backGlassOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.windshieldOptions.initializeComponent(
|
||||
resultMap.cmsContent.WindshieldDamageTypeQuestion, resultMap.cmsContent.WindshieldChipCountQuestion,
|
||||
resultMap.cmsContent.WindshieldReplaceOptionsQuestion, resultMap.damageOptions.windshieldOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.funnelFooter.initializeComponent(
|
||||
|
|
@ -121,6 +128,7 @@ export default {
|
|||
driverSideOptionsData: [],
|
||||
selectedRearReplaceOptions: [],
|
||||
windshieldOptionsData: [],
|
||||
selectedWindshieldOptions: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -146,6 +154,7 @@ export default {
|
|||
funnelSubHeader,
|
||||
replaceOptionsQuestion,
|
||||
damageLocationQuestion,
|
||||
windshieldOptions,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
<template>
|
||||
<div class="windshield-damage-type-question">
|
||||
<buttonQuestion
|
||||
v-if="isAvailable && answersToDisplay.length > 1"
|
||||
:questionText="questionText"
|
||||
:answers="answersToDisplay"
|
||||
:groupName="groupName"
|
||||
buttonType="listCard"
|
||||
v-model="selectedValues"
|
||||
validationRules="windshield-damage-required|checkForRepairAndReplace:@DamageLocationQuestion"
|
||||
:suppressError="suppressError"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
import store from "@/store";
|
||||
import { defineRule } from "vee-validate";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("windshield-damage-required", (value) => {
|
||||
if (!value || value.length < 1) {
|
||||
return "Please select windshield damage";
|
||||
}
|
||||
return true;
|
||||
});
|
||||
defineRule("checkForRepairAndReplace", (value, [other]) => {
|
||||
if (value === "Windshield-Chip" && other.toString().includes("Windshield") && other.length > 1) {
|
||||
return "checkForRepairAndReplace error"
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
export default ({
|
||||
name: "windshieldDamageTypeQuestion",
|
||||
data(){
|
||||
return {
|
||||
questionText: String,
|
||||
answersFromCms: Array,
|
||||
damageOptions: Object,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
isMultiSelect: Boolean,
|
||||
modelValue: Array,
|
||||
isAvailable: Boolean,
|
||||
name: String,
|
||||
groupName: String,
|
||||
suppressError: Boolean,
|
||||
},
|
||||
methods: {
|
||||
initializeComponent(cmsContent, damageOptions){
|
||||
this.questionText = cmsContent.QuestionText;
|
||||
this.answersFromCms = cmsContent.Answers;
|
||||
this.damageOptions = damageOptions;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
selectedValues: {
|
||||
get: function() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
}
|
||||
},
|
||||
damageOptionsMap(){
|
||||
return {
|
||||
Windshield: true,
|
||||
SideDoor: this.damageOptions.driverSideOptions.availableReplacementOptions || this.damageOptions.passengerSideOptions.availableReplacementOption ? true : false,
|
||||
RearWindow: this.damageOptions.backGlassOptions.availableReplacementOptions ? true : false,
|
||||
}
|
||||
},
|
||||
answersToDisplay(){
|
||||
// HARD CODED MOCK DATA FOR NOW
|
||||
return [
|
||||
{
|
||||
"Name": "Windshield-Crack",
|
||||
"Text": "Crack",
|
||||
"SubText": "My damage is larger than six inches.",
|
||||
"ImageId": "2cf13fbb-22d8-4b61-bd3d-3d413ea58c87",
|
||||
"AnswerImageUrl": "https://fixmyglass.safelite.com/Shared/images/icon-replace-desktop-ds.png"
|
||||
},
|
||||
{
|
||||
"Name": "Windshield-Chip",
|
||||
"Text": "Chip(s)",
|
||||
"SubText": "I have three or fewer chips smaller than six inches.",
|
||||
"ImageId": "faaa14d9-3650-4949-a687-7665962337b8",
|
||||
"AnswerImageUrl": "https://fixmyglass.safelite.com/Shared/images/icon-repair-desktop-ds.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
components: {
|
||||
buttonQuestion,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import windshieldChipCountQuestion from "@/layouts/vehicle-damage/windshield-options/windshield-chip-count-question/windshield-chip-count-question";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import store from "@/store";
|
||||
|
||||
jest.mock("@/store", () => { return {}; }, {virtual: true});
|
||||
|
||||
describe("windshield-chip-count-question.vue", () => {
|
||||
test("Selected chip count is emitted upon selection.", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({modelValueProp: ["One"]});
|
||||
|
||||
//Act
|
||||
wrapper.setValue({ modelValue: ["Two"] });
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.selectedChipCountValues).toEqual(["One"]);
|
||||
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ modelValue: ["Two"] }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Windshield-chip-count-question.vue", () => {
|
||||
test("Should display question and answers from api.", async () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper, cmsContent } = setupMocks({modelValueProp: ["One"]});
|
||||
|
||||
//Act
|
||||
windshieldChipCountQuestion.methods.initializeComponent.call(wrapper.vm, cmsContent);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questionText).toStrictEqual("How many chips are we repairing?");
|
||||
expect(wrapper.vm.answersFromCms).toStrictEqual([ { Name: 'One' }, { Name: 'Two' }, { Name: 'Three'} ]);
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
modelValueProp = ["Two"],
|
||||
groupName = "WindshieldChipCountQuestion",
|
||||
cmsQuestionText = "How many chips are we repairing?",
|
||||
cmsAnswers = [{Name: "One"}, {Name: "Two"}, {Name: "Three"}],
|
||||
dataFromStoreApi = [],
|
||||
}) {
|
||||
|
||||
//Mock store
|
||||
store.dispatch = jest.fn(() => dataFromStoreApi);
|
||||
store.getters = { vehicle: {year: 2019, make: 'honda', model: 'civc', style: '2 Door', category: 'CAR'} };
|
||||
const mountOptions = getMountOptions({
|
||||
store: {
|
||||
dispatch: store.dispatch,
|
||||
getters: store.getters,
|
||||
},
|
||||
});
|
||||
|
||||
//Mock props
|
||||
mountOptions.propsData = {
|
||||
modelValue: modelValueProp
|
||||
};
|
||||
|
||||
const wrapper = shallowMount(windshieldChipCountQuestion, mountOptions);
|
||||
|
||||
//Mock CMS content
|
||||
const cmsContent = {
|
||||
groupName: groupName,
|
||||
QuestionText: cmsQuestionText,
|
||||
Answers: cmsAnswers,
|
||||
};
|
||||
const damageOptions = dataFromStoreApi;
|
||||
return { wrapper, cmsContent, damageOptions };
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<transition name="fade">
|
||||
<div class="windshield-chip-count-question">
|
||||
<buttonQuestion
|
||||
v-if="isAvailable"
|
||||
:questionText="questionText"
|
||||
:answers="answersFromCms"
|
||||
:groupName="groupName"
|
||||
buttonType="listButtonHorizontal"
|
||||
v-model="selectedChipCountValues"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
|
||||
export default ({
|
||||
name: "windshieldOptions",
|
||||
data(){
|
||||
return {
|
||||
questionText: String,
|
||||
answersFromCms: Array
|
||||
}
|
||||
},
|
||||
props: {
|
||||
modelValue: Array,
|
||||
groupName: String,
|
||||
isAvailable: Boolean,
|
||||
},
|
||||
methods: {
|
||||
initializeComponent(cmsContent){
|
||||
this.questionText = cmsContent.QuestionText;
|
||||
this.answersFromCms = cmsContent.Answers;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedChipCountValues: {
|
||||
get: function() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
}
|
||||
},
|
||||
},
|
||||
components: {
|
||||
buttonQuestion,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import windshieldDamageTypeQuestion from"@/layouts/vehicle-damage/windshield-options/windshield-damage-type-question/windshield-damage-type-question";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import store from "@/store";
|
||||
|
||||
jest.mock("@/store", () => { return {}; }, {virtual: true});
|
||||
|
||||
describe("windshield-damage-type-question.vue", () => {
|
||||
test("Selected chip count is emitted upon selection.", async () => {
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({modelValueProp: ["Repair"]});
|
||||
|
||||
//Act
|
||||
wrapper.setValue({ modelValue: ["Replace"] });
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.selectedValues).toEqual(["Repair"]);
|
||||
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ modelValue: ["Replace"] }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("windshield-damage-type-question.vue", () => {
|
||||
test("Should display question and answers from api.", async () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper, cmsContent } = setupMocks({modelValueProp: ["Repair"]});
|
||||
|
||||
//Act
|
||||
windshieldDamageTypeQuestion.methods.initializeComponent.call(wrapper.vm, cmsContent);
|
||||
|
||||
//Assert
|
||||
expect(wrapper.vm.questionText).toStrictEqual("What's your windshield damage?");
|
||||
expect(wrapper.vm.answersFromCms).toStrictEqual([ { Name: 'Repair' }, { Name: 'Replace' } ]);
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({
|
||||
modelValueProp = ["Two"],
|
||||
groupName = "WindshieldDamageTypeQuestion",
|
||||
cmsQuestionText = "What's your windshield damage?",
|
||||
cmsAnswers = [{Name: "Repair"}, {Name: "Replace"}],
|
||||
dataFromStoreApi = [],
|
||||
}) {
|
||||
|
||||
//Mock store
|
||||
store.dispatch = jest.fn(() => dataFromStoreApi);
|
||||
store.getters = { vehicle: {year: 2019, make: 'honda', model: 'civc', style: '2 Door', category: 'CAR'} };
|
||||
const mountOptions = getMountOptions({
|
||||
store: {
|
||||
dispatch: store.dispatch,
|
||||
getters: store.getters,
|
||||
},
|
||||
});
|
||||
|
||||
//Mock props
|
||||
mountOptions.propsData = {
|
||||
modelValue: modelValueProp
|
||||
};
|
||||
|
||||
const wrapper = shallowMount(windshieldDamageTypeQuestion, mountOptions);
|
||||
|
||||
//Mock CMS content
|
||||
const cmsContent = {
|
||||
groupName: groupName,
|
||||
QuestionText: cmsQuestionText,
|
||||
Answers: cmsAnswers,
|
||||
};
|
||||
const damageOptions = dataFromStoreApi;
|
||||
return { wrapper, cmsContent, damageOptions };
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<transition name="fade">
|
||||
<div class="windshield-damage-type-question">
|
||||
<buttonQuestion
|
||||
v-if="isAvailable"
|
||||
:questionText="questionText"
|
||||
:answers="answersFromCms"
|
||||
:groupName="groupName"
|
||||
buttonType="listCard"
|
||||
v-model="selectedValues"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
//import { defineRule } from "vee-validate";
|
||||
|
||||
//DEFINE VALIDATION RULES
|
||||
// add these to the button component above:
|
||||
// validationRules="windshield-damage-required|checkForRepairAndReplace:@DamageLocationQuestion"
|
||||
// :suppressError="suppressError"
|
||||
// defineRule("windshield-damage-required", (value) => {
|
||||
// if (!value || value.length < 1) {
|
||||
// return "Please select windshield damage";
|
||||
// }
|
||||
// return true;
|
||||
// });
|
||||
// defineRule("checkForRepairAndReplace", (value, [other]) => {
|
||||
// if (value === "Windshield-Chip" && other.toString().includes("Windshield") && other.length > 1) {
|
||||
// return "checkForRepairAndReplace error"
|
||||
// }
|
||||
// return true;
|
||||
// });
|
||||
|
||||
export default ({
|
||||
name: "windshieldDamageTypeQuestion",
|
||||
data(){
|
||||
return {
|
||||
questionText: String,
|
||||
answersFromCms: Array
|
||||
}
|
||||
},
|
||||
props: {
|
||||
modelValue: Array,
|
||||
groupName: String,
|
||||
isAvailable: Boolean,
|
||||
suppressError: Boolean,
|
||||
},
|
||||
methods: {
|
||||
initializeComponent(cmsContent){
|
||||
this.questionText = cmsContent.QuestionText;
|
||||
this.answersFromCms = cmsContent.Answers;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedValues: {
|
||||
get: function() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
}
|
||||
},
|
||||
},
|
||||
components: {
|
||||
buttonQuestion,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,26 +1,112 @@
|
|||
<template>
|
||||
<div class="windshield-options">
|
||||
<windshieldDamageTypeQuestion
|
||||
ref="windshieldDamageType"
|
||||
v-model="selectedWindshieldDamageTypes"
|
||||
groupName="windshieldDamageTypeQuestion"
|
||||
:isAvailable="showWindshieldDamageTypeQuestion"
|
||||
:suppressError="suppressError"
|
||||
/>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div class="windshield-options" aria-live="polite">
|
||||
<windshieldDamageTypeQuestion ref="windshieldDamageTypeQuestion"
|
||||
:isAvailable=isWindshieldDamageLocation
|
||||
:suppressError="suppressError"
|
||||
groupName="WindshieldDamageTypeQuestion"
|
||||
v-model="selectedWindshieldDamageTypeValues"
|
||||
/>
|
||||
<windshieldChipCountQuestion ref="windshieldChipCountQuestion"
|
||||
:isAvailable=isRepairOptionSelected
|
||||
groupName="WindshieldChipCountQuestion"
|
||||
v-model="selectedWindshieldChipCountValues"
|
||||
/>
|
||||
<replaceOptionsQuestion ref="replaceOptionsQuestion"
|
||||
:isAvailable=isReplaceOptionSelected
|
||||
groupName="WindshieldReplaceOptions"
|
||||
v-model="selectedWindshieldReplaceOptionsValues"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import windshieldDamageTypeQuestion from "@/layouts/vehicle-damage/windshield-damage-type-question/windshield-damage-type-question";
|
||||
|
||||
import windshieldDamageTypeQuestion from"@/layouts/vehicle-damage/windshield-options/windshield-damage-type-question/windshield-damage-type-question";
|
||||
import windshieldChipCountQuestion from"@/layouts/vehicle-damage/windshield-options/windshield-chip-count-question/windshield-chip-count-question";
|
||||
import replaceOptionsQuestion from"@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
||||
export default ({
|
||||
name: "windshieldOptions",
|
||||
|
||||
props: {
|
||||
showWindshieldDamageTypeQuestion: Boolean,
|
||||
suppressError: Boolean,
|
||||
modelValue: Array,
|
||||
selectedDamageLocations: Array,
|
||||
selectedChipCount: Array,
|
||||
selectedReplaceOptions: Array,
|
||||
suppressError: Boolean
|
||||
},
|
||||
|
||||
methods: {
|
||||
initializeComponent(windshieldDamageTypeQuestionFromCms, windshieldChipCountQuestionFromCms,
|
||||
windshieldReplaceOptionsQuestionFromCms, windshieldAvailableReplacementOptions){
|
||||
|
||||
this.$refs.windshieldDamageTypeQuestion.initializeComponent(windshieldDamageTypeQuestionFromCms);
|
||||
this.$refs.windshieldChipCountQuestion.initializeComponent(windshieldChipCountQuestionFromCms);
|
||||
this.$refs.replaceOptionsQuestion.initializeComponent(windshieldReplaceOptionsQuestionFromCms, windshieldAvailableReplacementOptions);
|
||||
},
|
||||
getWindshieldOptions(selectedWindshieldDamageType, selectedWindshieldChipCount, selectedWindshieldReplaceOptions){
|
||||
return {
|
||||
selectedWindshieldDamageType: selectedWindshieldDamageType,
|
||||
selectedWindshieldChipCount: selectedWindshieldChipCount,
|
||||
selectedWindshieldReplaceOptions: selectedWindshieldReplaceOptions
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
selectedValues: {
|
||||
get: function() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
}
|
||||
},
|
||||
selectedWindshieldDamageTypeValues:{
|
||||
get: function() {
|
||||
return this.selectedValues.selectedWindshieldDamageType;
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.selectedValues = this.getWindshieldOptions(newValue, null, null);
|
||||
}
|
||||
},
|
||||
selectedWindshieldChipCountValues: {
|
||||
get: function() {
|
||||
return this.selectedValues.selectedChipCount;
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.selectedValues = this.getWindshieldOptions(this.selectedWindshieldDamageTypeValues, newValue, null);
|
||||
}
|
||||
},
|
||||
selectedWindshieldReplaceOptionsValues: {
|
||||
get: function() {
|
||||
return this.selectedValues.selectedWindshieldReplaceOptions;
|
||||
},
|
||||
set: function(newValue) {
|
||||
this.selectedValues = this.getWindshieldOptions(this.selectedWindshieldDamageTypeValues, null, newValue);
|
||||
}
|
||||
},
|
||||
isWindshieldDamageLocation() {
|
||||
return this.selectedDamageLocations.some(selectedDamages =>
|
||||
{
|
||||
const categoryAndGlass = selectedDamages.split('-'); //ie: "Suv-Windshield" Splits the answers into [0]"Suv" [1]"Windshield"
|
||||
return Boolean(categoryAndGlass[1].toUpperCase() === "WINDSHIELD");
|
||||
});
|
||||
},
|
||||
isRepairOptionSelected(){
|
||||
if (!this.selectedWindshieldDamageTypeValues) return false;
|
||||
|
||||
return this.selectedWindshieldDamageTypeValues.some(val => val.toUpperCase() === "REPAIR") && this.isWindshieldDamageLocation;
|
||||
},
|
||||
isReplaceOptionSelected(){
|
||||
if (!this.selectedWindshieldDamageTypeValues) return false;
|
||||
|
||||
return this.selectedWindshieldDamageTypeValues.some(val => val.toUpperCase() === "REPLACE") && this.isWindshieldDamageLocation;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
windshieldDamageTypeQuestion,
|
||||
windshieldChipCountQuestion,
|
||||
replaceOptionsQuestion
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
@ -11,6 +11,7 @@ import store from "@/store";
|
|||
import ComponentTest from "@/layouts/component-test/component-test.vue";
|
||||
import AddressPOC from "@/layouts/address-poc/address-poc.vue";
|
||||
import FormTest from "@/layouts/form-test/form-test.vue";
|
||||
import NestedRadio from "@/layouts/nested-radio-poc/nested-radio.vue";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
|
|
@ -33,6 +34,11 @@ const routes = [
|
|||
name: "FormTest",
|
||||
component: FormTest,
|
||||
},
|
||||
{
|
||||
path: "/nested-radio", // This is a temporary route for testing.
|
||||
name: "NestedRadio",
|
||||
component: NestedRadio,
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
name: "root",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
}
|
||||
&.ui-radio,
|
||||
&.ui-checkbox {
|
||||
input[type=checkbox],
|
||||
input[type=radio],
|
||||
input[type=radio]+label:before,
|
||||
input[type=checkbox]+label:before {
|
||||
border: 1px solid $red;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<template>
|
||||
<!-- Checkbox groups MUST be wrapped in a <fieldset> and <legend> tag -->
|
||||
<div class="ui-checkbox d-flex" :class="[hasError ? 'has-error' : '']">
|
||||
<input
|
||||
type="checkbox"
|
||||
aria-checked="false"
|
||||
:name="checkboxName"
|
||||
:id="buttonID"
|
||||
:tabindex="tabIndex"
|
||||
:aria-required="isRequired"
|
||||
<div class="form-check ui-checkbox" :class="[hasError ? 'has-error' : '']">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
aria-checked="false"
|
||||
:name="checkboxName"
|
||||
:id="buttonID"
|
||||
:tabindex="tabIndex"
|
||||
:aria-required="isRequired"
|
||||
/>
|
||||
<label class="d-flex align-items-center" :for="buttonID">
|
||||
<label class="d-flex align-items-start" :for="buttonID">
|
||||
<p v-if="checkboxLabel" class="m-0">{{ checkboxLabel }}</p>
|
||||
<span v-if="screenReaderOnlyText" class="sr-only">{{
|
||||
screenReaderOnlyText
|
||||
|
|
@ -33,61 +33,22 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-checkbox {
|
||||
position: relative;
|
||||
input[type="checkbox"] {
|
||||
position: absolute !important;
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
overflow: hidden;
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
+ label {
|
||||
display: block;
|
||||
position: relative;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
<style lang="scss" scoped>
|
||||
.form-check {
|
||||
.form-check-input {
|
||||
border: 1px solid $gray-500;
|
||||
border-radius: 2px;
|
||||
&:checked {
|
||||
background-size: 125%;
|
||||
border: 1px solid $blue;
|
||||
}
|
||||
+ label::before {
|
||||
content: "";
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: white;
|
||||
border: 1px solid $gray-500;
|
||||
border-radius: 2px;
|
||||
}
|
||||
&:checked + label::before {
|
||||
background: $blue;
|
||||
}
|
||||
&:checked + label::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 2px;
|
||||
border-left: 2px solid $white;
|
||||
border-bottom: 2px solid $white;
|
||||
height: 6px;
|
||||
width: 12px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
&:hover + label::before {
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 4px $blue-300;
|
||||
}
|
||||
&:focus + label::before {
|
||||
box-shadow: 0 0 0 2px $blue;
|
||||
}
|
||||
&:focus:checked + label::before {
|
||||
box-shadow: 0 0 0 2px transparent;
|
||||
}
|
||||
&:disabled + label {
|
||||
color: $gray-200;
|
||||
}
|
||||
&:disabled + label::before {
|
||||
background: $gray-200;
|
||||
}
|
||||
&:hover {
|
||||
.form-check-input {
|
||||
box-shadow: 0 0 0 4px $blue-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
:aria-required="isRequired"
|
||||
:data-focus-target="groupName"
|
||||
v-model="checkValue"
|
||||
@change="!selectingInitiatesLoad ? handleCheckChange : ''"
|
||||
@change="!selectingInitiatesLoad ? handleCheckChange() : ''"
|
||||
/>
|
||||
<label
|
||||
tabindex="-1"
|
||||
|
|
@ -133,9 +133,11 @@ export default {
|
|||
height: 0;
|
||||
&:focus-visible + label {
|
||||
box-shadow: 0 0 0 2px $blue;
|
||||
z-index: 2;
|
||||
}
|
||||
&:focus + label {
|
||||
box-shadow: 0 0 0 2px $blue;
|
||||
z-index: 3;
|
||||
}
|
||||
&:checked + label {
|
||||
background: $blue-100;
|
||||
|
|
@ -157,7 +159,7 @@ export default {
|
|||
&:hover {
|
||||
box-shadow: 0 0 0 4px $blue-300;
|
||||
cursor: pointer;
|
||||
z-index: 3 !important;
|
||||
z-index: 4 !important;
|
||||
}
|
||||
+ p {
|
||||
display: none;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
:aria-required="isRequired"
|
||||
:data-focus-target="groupName"
|
||||
v-model="checkValue"
|
||||
@change="!selectingInitiatesLoad ? handleCheckChange : ''"
|
||||
@change="!selectingInitiatesLoad ? handleCheckChange() : ''"
|
||||
>
|
||||
<label
|
||||
tabindex="-1"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
:data-focus-target="groupName"
|
||||
@click="handleChange(value)"
|
||||
v-model="checkValue"
|
||||
@change="handleCheckChange"
|
||||
@change="handleCheckChange()"
|
||||
/>
|
||||
<label
|
||||
:for="buttonID"
|
||||
|
|
@ -173,6 +173,7 @@ export default {
|
|||
&:checked + label {
|
||||
p {
|
||||
color: $black;
|
||||
font-weight: 500;
|
||||
}
|
||||
.sub-copy {
|
||||
color: $gray-600;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
<template>
|
||||
<!-- Checkbox groups MUST be wrapped in a <fieldset> and <legend> tag and must contain tabindex -->
|
||||
<div class="ui-radio d-flex" :class="[hasError ? 'has-error' : '']">
|
||||
<div class="ui-radio form-check" :class="[hasError ? 'has-error' : '']">
|
||||
<input
|
||||
type="radio"
|
||||
class="form-check-input"
|
||||
aria-checked="false"
|
||||
:name="groupName"
|
||||
:id="buttonID"
|
||||
:aria-required="isRequired"
|
||||
:value="value"
|
||||
:v-model="checkValue"
|
||||
@change="handleCheckChanged"
|
||||
@change="handleCheckChanged()"
|
||||
/>
|
||||
<label class="d-flex align-items-center" :for="buttonID">
|
||||
<label class="d-flex align-items-start form-check-label" :for="buttonID">
|
||||
<p v-if="buttonLabel" class="m-0">{{ buttonLabel }}</p>
|
||||
<span v-if="screenReaderOnlyText" class="sr-only">{{
|
||||
screenReaderOnlyText
|
||||
|
|
@ -77,62 +78,25 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-radio {
|
||||
position: relative;
|
||||
input[type="radio"] {
|
||||
position: absolute !important;
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
overflow: hidden;
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
+ label {
|
||||
display: block;
|
||||
position: relative;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
+ label::before {
|
||||
content: "";
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: white;
|
||||
border: 1px solid $gray-500;
|
||||
border-radius: 50%;
|
||||
}
|
||||
&:checked + label::before {
|
||||
background: $white;
|
||||
<style lang="scss" scoped>
|
||||
.form-check {
|
||||
.form-check-input {
|
||||
border: 1px solid $gray-500;
|
||||
border-radius: 100%;
|
||||
margin-right: .5rem;
|
||||
&:checked {
|
||||
background-color: $white;
|
||||
background-size: 71%;
|
||||
border: 1px solid $blue;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50' xml:space='preserve'%3e%3ccircle cx='25' cy='25' r='25' fill='%231574A1'/%3e%3c/svg%3e");
|
||||
}
|
||||
&:checked + label::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 3px;
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
transform: rotate(-45deg);
|
||||
border: 5px solid $blue;
|
||||
border-radius: 50%;
|
||||
}
|
||||
&:hover + label::before {
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 4px $blue-300;
|
||||
}
|
||||
&:focus + label::before {
|
||||
box-shadow: 0 0 0 2px $blue;
|
||||
}
|
||||
&:focus:checked + label::before {
|
||||
box-shadow: 0 0 0 2px transparent;
|
||||
}
|
||||
&:disabled + label {
|
||||
color: $gray-200;
|
||||
}
|
||||
&:disabled + label::before {
|
||||
background: $gray-200;
|
||||
}
|
||||
&:hover {
|
||||
.form-check-input {
|
||||
box-shadow: 0 0 0 4px $blue-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue