commit
8850c11503
17 changed files with 473 additions and 174 deletions
12
src/constants/error-messages.js
Normal file
12
src/constants/error-messages.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
const errorMessages = {
|
||||
DAMAGE_LOCATION_REQUIRED: "Please select damage location",
|
||||
DAMAGE_SIDE_REQUIRED: "Please select vehicle side",
|
||||
DRIVER_SIDE_OPTIONS_REQUIRED: "Please select window",
|
||||
PASSENGER_SIDE_OPTIONS_REQUIRED: "Please select window",
|
||||
WINDSHIELD_DAMAGE_TYPE_REQUIRED: "Please select windshield damage",
|
||||
WINDSHIELD_CHIP_COUNT_REQUIRED: "Please select chip(s)",
|
||||
WINSHIELD_REPLACE_OPTIONS_REQUIRED: "Please select windshield part",
|
||||
REPLACE_OPTIONS_REQUIRED: "Please select rear window type",
|
||||
};
|
||||
|
||||
export { errorMessages };
|
||||
8
src/helpers/validation-rules.js
Normal file
8
src/helpers/validation-rules.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export function required(errorMessage) {
|
||||
return (value) => {
|
||||
if (!value || value.length < 1) {
|
||||
return errorMessage;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
29
src/helpers/validation-rules.spec.js
Normal file
29
src/helpers/validation-rules.spec.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { required } from "@/helpers/validation-rules";
|
||||
|
||||
describe("validation-rules.vue", () => {
|
||||
test("required rules should return error if value missing", () => {
|
||||
|
||||
//Arrange
|
||||
const testFn = required("an error");
|
||||
|
||||
//Act
|
||||
const testResponse = testFn();
|
||||
|
||||
//Assert
|
||||
expect(testResponse).toBe("an error");
|
||||
});
|
||||
});
|
||||
|
||||
describe("validation-rules.vue", () => {
|
||||
test("required rules should return true if value present", () => {
|
||||
|
||||
//Arrange
|
||||
const testFn = required("an error");
|
||||
|
||||
//Act
|
||||
const testResponse = testFn('some value');
|
||||
|
||||
//Assert
|
||||
expect(testResponse).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -15,27 +15,38 @@
|
|||
groupName="DamageLocationQuestion"
|
||||
/>
|
||||
<windshieldOptions
|
||||
ref="windshieldOptions"
|
||||
:showWindshieldDamageTypeQuestion="values.DamageLocationQuestion && values.DamageLocationQuestion.toString().includes('-Windshield')"
|
||||
:suppressError="errors.windshieldDamageTypeQuestion && errors.windshieldDamageTypeQuestion.startsWith('checkForRepairAndReplace')"
|
||||
ref="windshieldOptions"
|
||||
v-model="selectedWindshieldOptions"
|
||||
:hasRepairReplaceConflict="hasRepairReplaceConflict"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<alert
|
||||
class="my-3"
|
||||
v-if="errors.windshieldDamageTypeQuestion && errors.windshieldDamageTypeQuestion.startsWith('checkForRepairAndReplace')"
|
||||
v-show="hasRepairReplaceConflict"
|
||||
alertClass="alert-danger"
|
||||
alertHeadline="You'll need to schedule separate appointments"
|
||||
alertCopy="Vehicle service requiring both glass repair and replacement must be scheduled separately, as they're performed by different technicians."
|
||||
alertCopy="Vehicle service requiring both glass repair and replacement must be scheduled separately, as they're performed by different technicians. Continue scheduling your first service now, and then come back to schedule the second service."
|
||||
:isDismissible="false"
|
||||
/>
|
||||
<sideDoorOptions
|
||||
ref="sideDoorOptions"
|
||||
groupName="SideDoorSideQuestion"
|
||||
v-model="sideDoorOptionsData"
|
||||
v-show="!hasRepairReplaceConflict"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="driverSideOptions"
|
||||
isAvailable
|
||||
v-model="driverSideOptionsData"
|
||||
groupName="DriverSideReplaceOptionsQuestion"
|
||||
ref="backGlassOptions"
|
||||
:isAvailable="isRearWindowDamageLocation && !hasRepairReplaceConflict"
|
||||
v-model="selectedRearReplaceOptions"
|
||||
groupName="BackGlassReplaceOptionsQuestion"
|
||||
validationRules="replace-options-required"
|
||||
/>
|
||||
<funnel-footer
|
||||
ref="funnelFooter"
|
||||
:isDisabled="!meta.valid"
|
||||
@back-clicked="backButtonAction"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
/>
|
||||
|
||||
<!-- KEEP TEMPORARILY FOR TROUBLESHOOTING VALIDATION -->
|
||||
|
|
@ -60,19 +71,23 @@ 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 sideDoorOptions from "@/layouts/vehicle-damage/side-door-options/side-door-options";
|
||||
import windshieldOptions from "@/layouts/vehicle-damage/windshield-options/windshield-options";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
|
||||
import { Form } from 'vee-validate';
|
||||
|
||||
|
||||
// Supporting files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import store from "@/store";
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED));
|
||||
|
||||
export default {
|
||||
name: "form-test",
|
||||
|
|
@ -110,12 +125,19 @@ export default {
|
|||
vm.$refs.funnelSubHeader.initializeComponent(
|
||||
resultMap.cmsContent.FunnelSubHeaderWidget
|
||||
);
|
||||
vm.$refs.driverSideOptions.initializeComponent(
|
||||
resultMap.cmsContent.DriverSideReplaceOptionsQuestion, resultMap.damageOptions.driverSideOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.damageLocation.initializeComponent(
|
||||
resultMap.cmsContent.DamageLocationQuestion, resultMap.damageOptions
|
||||
);
|
||||
vm.$refs.sideDoorOptions.initializeComponent(
|
||||
resultMap.cmsContent.SideDoorSideQuestion, resultMap.cmsContent.DriverSideReplaceOptionsQuestion, resultMap.cmsContent.PassengerSideReplaceOptionsQuestion, resultMap.damageOptions.driverSideOptions.availableReplacementOptions, resultMap.damageOptions.passengerSideOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.windshieldOptions.initializeComponent(
|
||||
resultMap.cmsContent.WindshieldDamageTypeQuestion, resultMap.cmsContent.WindshieldChipCountQuestion,
|
||||
resultMap.cmsContent.WindshieldReplaceOptionsQuestion, resultMap.damageOptions.windshieldOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.backGlassOptions.initializeComponent(
|
||||
resultMap.cmsContent.RearReplaceOptionsQuestion, resultMap.damageOptions.backGlassOptions.availableReplacementOptions
|
||||
);
|
||||
vm.$refs.funnelFooter.initializeComponent(
|
||||
resultMap.cmsContent.FunnelFooterWidget
|
||||
);
|
||||
|
|
@ -124,26 +146,20 @@ export default {
|
|||
data(){
|
||||
return {
|
||||
selectedDamageLocations: [],
|
||||
driverSideOptionsData: [],
|
||||
sideDoorOptionsData: {
|
||||
selectedDoorSides: [],
|
||||
selectedDriverSideReplaceOptions: [],
|
||||
selectedPassengerSideReplaceOptions: []
|
||||
},
|
||||
selectedWindshieldOptions: [],
|
||||
selectedRearReplaceOptions: [],
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Form,
|
||||
funnelHeader,
|
||||
vehicleBanner,
|
||||
funnelSubHeader,
|
||||
damageLocationQuestion,
|
||||
replaceOptionsQuestion,
|
||||
funnelFooter,
|
||||
windshieldOptions,
|
||||
alert,
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
return store.getters.vehicle.carId !== null;
|
||||
},
|
||||
resetDependentState() {
|
||||
// Invokes
|
||||
store.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
||||
},
|
||||
onSubmit(values) {
|
||||
|
|
@ -165,5 +181,64 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isWindshieldDamageLocation() {
|
||||
return this.selectedDamageLocations.some(selectedDamages =>
|
||||
{
|
||||
return selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD;
|
||||
});
|
||||
},
|
||||
isSideDoorDamageLocation() {
|
||||
return this.selectedDamageLocations.some(selectedDamages =>
|
||||
{
|
||||
return selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR;
|
||||
});
|
||||
},
|
||||
isRearWindowDamageLocation() {
|
||||
return this.selectedDamageLocations.some(selectedDamages =>
|
||||
{
|
||||
return selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW;
|
||||
});
|
||||
},
|
||||
isWindshieldRepair() {
|
||||
if (!this.isWindshieldDamageLocation) return false;
|
||||
|
||||
return this.selectedWindshieldOptions.selectedWindshieldDamageType && this.selectedWindshieldOptions.selectedWindshieldDamageType.some(selectedDamageType =>
|
||||
{
|
||||
return selectedDamageType.toUpperCase() === "REPAIR";
|
||||
});
|
||||
},
|
||||
isDriverSideReplace() {
|
||||
if (!this.isSideDoorDamageLocation) return false;
|
||||
|
||||
return this.sideDoorOptionsData.selectedDoorSides.some(selectedDriverSide =>
|
||||
{
|
||||
return selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE;
|
||||
});
|
||||
},
|
||||
isPassengerSideReplace() {
|
||||
if (!this.isSideDoorDamageLocation) return false;
|
||||
|
||||
return this.sideDoorOptionsData.selectedDoorSides.some(selectedPassengerSide =>
|
||||
{
|
||||
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
|
||||
});
|
||||
},
|
||||
hasRepairReplaceConflict() {
|
||||
return this.isWindshieldDamageLocation && this.selectedDamageLocations.length > 1 && this.isWindshieldRepair;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
funnelHeader,
|
||||
funnelFooter,
|
||||
vehicleBanner,
|
||||
funnelSubHeader,
|
||||
sideDoorOptions,
|
||||
damageLocationQuestion,
|
||||
windshieldOptions,
|
||||
replaceOptionsQuestion,
|
||||
Form,
|
||||
alert,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
v-model="selectedValues"
|
||||
validationRules="damage-location-required"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -17,14 +16,11 @@
|
|||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
import store from "@/store";
|
||||
import { defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("damage-location-required", (value) => {
|
||||
if (!value || value.length < 1) {
|
||||
return "Please select damage location";
|
||||
}
|
||||
return true;
|
||||
});
|
||||
defineRule("damage-location-required", required(errorMessages.DAMAGE_LOCATION_REQUIRED));
|
||||
|
||||
export default ({
|
||||
name: "damageLocationQuestion",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
:groupName="groupName"
|
||||
buttonType="listCard"
|
||||
v-model="selectedValues"
|
||||
validationRules="replace-options-required"
|
||||
:validationRules="validationRules"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
|
|
@ -18,15 +18,6 @@
|
|||
<script>
|
||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
import store from "@/store";
|
||||
import { defineRule } from "vee-validate";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("replace-options-required", (value) => {
|
||||
if (!value || value.length < 1) {
|
||||
return "Please select window";
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
export default ({
|
||||
name: "replaceOptionsQuestion",
|
||||
|
|
@ -43,6 +34,7 @@ export default ({
|
|||
groupName: String,
|
||||
modelValue: Array,
|
||||
isMultiSelect: Boolean,
|
||||
validationRules: String,
|
||||
},
|
||||
methods: {
|
||||
initializeComponent(cmsContent, replaceOptions){
|
||||
|
|
|
|||
|
|
@ -9,13 +9,28 @@
|
|||
:groupName="groupName"
|
||||
buttonType="listCard"
|
||||
v-model="selectedDoorSidesValues"
|
||||
validationRules="damage-side-required"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<replaceOptionsQuestion ref="driverSideOptions" :isAvailable="isDriverSideReplaceOptionsQuestionAvailable" groupName="driverSideOptions" filterByVehicleCategory isMultiSelect v-model="selectedDriverSideReplaceOptionsValues" />
|
||||
|
||||
<replaceOptionsQuestion ref="passengerSideOptions" :isAvailable="isPassengerSideReplaceOptionsQuestionAvailable" groupName="passengerSideOptions" filterByVehicleCategory isMultiSelect v-model="selectedPassengerSideReplaceOptionsValues" />
|
||||
<replaceOptionsQuestion
|
||||
ref="driverSideOptions"
|
||||
:isAvailable="isDriverSideReplaceOptionsQuestionAvailable"
|
||||
groupName="driverSideOptions"
|
||||
isMultiSelect
|
||||
filterByVehicleCategory
|
||||
v-model="selectedDriverSideReplaceOptionsValues"
|
||||
validationRules="driver-side-options-required"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="passengerSideOptions"
|
||||
:isAvailable="isPassengerSideReplaceOptionsQuestionAvailable"
|
||||
groupName="passengerSideOptions"
|
||||
isMultiSelect
|
||||
filterByVehicleCategory
|
||||
v-model="selectedPassengerSideReplaceOptionsValues"
|
||||
validationRules="passenger-side-options-required"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -23,6 +38,14 @@
|
|||
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
||||
import store from "@/store";
|
||||
import { defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("damage-side-required", required(errorMessages.DAMAGE_SIDE_REQUIRED));
|
||||
defineRule("driver-side-options-required", required(errorMessages.DRIVER_SIDE_OPTIONS_REQUIRED));
|
||||
defineRule("passenger-side-options-required", required(errorMessages.PASSENGER_SIDE_OPTIONS_REQUIRED));
|
||||
|
||||
export default ({
|
||||
name: "sideDoorOptions",
|
||||
|
|
|
|||
|
|
@ -13,12 +13,13 @@ import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-que
|
|||
import { settleAllPromises } from "@/helpers/layout-helper.js";
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { shallowMount } from "@vue/test-utils";
|
||||
import { mount, flushPromises } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import { nextTick } from "vue";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { storeMutations } from "@/constants/store-mutations";
|
||||
import store from "@/store";
|
||||
import { validate } from "vee-validate";
|
||||
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
||||
|
||||
// Mock our module for promises.
|
||||
|
|
@ -38,7 +39,9 @@ jest.mock("@/store", () => ({
|
|||
getters: {
|
||||
vehicle: {
|
||||
carId: "C00000000",
|
||||
image: "test.jpg",
|
||||
},
|
||||
eventBusItem: jest.fn(),
|
||||
damage: {
|
||||
glassToReplace: []
|
||||
},
|
||||
|
|
@ -216,6 +219,11 @@ describe("vehicle-damage.vue", () => {
|
|||
mountOptionsMockData: {
|
||||
router: { navigateAfterSave: jest.fn(), },
|
||||
actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },],
|
||||
store: {
|
||||
getters: {
|
||||
vehicle: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -277,7 +285,13 @@ describe("vehicle-damage.vue", () => {
|
|||
pageHeaderWidgetHeaderText: "",
|
||||
mountOptionsMockData: {
|
||||
router: { navigate: jest.fn(), },
|
||||
actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },],},
|
||||
actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },],
|
||||
store: {
|
||||
getters: {
|
||||
vehicle: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.selectedDamageLocations = ["Windshield"];
|
||||
|
|
@ -361,7 +375,13 @@ describe("vehicle-damage.vue", () => {
|
|||
pageHeaderWidgetHeaderText: "",
|
||||
mountOptionsMockData: {
|
||||
router: { navigateAfterSave: jest.fn(), },
|
||||
actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },],},
|
||||
actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },],
|
||||
store: {
|
||||
getters: {
|
||||
vehicle: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.selectedDamageLocations = ["Windshield"];
|
||||
|
|
@ -400,7 +420,13 @@ describe("vehicle-damage.vue", () => {
|
|||
pageHeaderWidgetHeaderText: "",
|
||||
mountOptionsMockData: {
|
||||
router: { navigate: jest.fn(), },
|
||||
actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },],},
|
||||
actionList: [{ actionName: storeActions.GET_PARTS_OR_QUESTIONS, data: partsData, },],
|
||||
store: {
|
||||
getters: {
|
||||
vehicle: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.selectedDamageLocations = ["Windshield"];
|
||||
|
|
@ -618,7 +644,7 @@ describe("vehicle-damage.vue", () => {
|
|||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
store.getters = { vehicle: { carId: "C0000000" }, damage: { glassToReplace: [{location: damageLocation}] }, isRepair: true};
|
||||
store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{location: damageLocation}] }, isRepair: true};
|
||||
|
||||
var glassSelections = wrapper.vm.getDamageLocationsFromStore();
|
||||
|
||||
|
|
@ -654,6 +680,7 @@ describe("vehicle-damage.vue", () => {
|
|||
store.getters = {
|
||||
vehicle:
|
||||
{ carId: "C0000000" },
|
||||
eventBusItem: jest.fn(),
|
||||
damage:
|
||||
{
|
||||
glassToReplace: [{location: damageLocation, name: damageName}],
|
||||
|
|
@ -689,7 +716,7 @@ describe("vehicle-damage.vue", () => {
|
|||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
store.getters = { vehicle: { carId: "C0000000" }, damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true};
|
||||
store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true};
|
||||
|
||||
var glassSelections = wrapper.vm.getDriverSideReplaceOptionsFromStore();
|
||||
|
||||
|
|
@ -718,7 +745,7 @@ describe("vehicle-damage.vue", () => {
|
|||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
store.getters = { vehicle: { carId: "C0000000" }, damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true};
|
||||
store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true};
|
||||
|
||||
var glassSelections = wrapper.vm.getPassengerSideReplaceOptionsFromStore();
|
||||
|
||||
|
|
@ -745,7 +772,7 @@ describe("vehicle-damage.vue", () => {
|
|||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
||||
store.getters = { vehicle: { carId: "C0000000" }, damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true};
|
||||
store.getters = { vehicle: { carId: "C0000000" }, eventBusItem: jest.fn(), damage: { glassToReplace: [{location: damageLocation, name: damageName}] }, isRepair: true};
|
||||
|
||||
var glassSelections = wrapper.vm.getRearReplaceOptionsFromStore();
|
||||
|
||||
|
|
@ -755,6 +782,72 @@ describe("vehicle-damage.vue", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("vehicle-damage.vue", () => {
|
||||
test("when onInvalidSubmit is triggered with errors focus will be put on the first element with an error", async () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
const mockedValidationPayload = {
|
||||
values: {},
|
||||
errors: {
|
||||
driverSideOptions: 'Please select window',
|
||||
passengerSideOptions: 'Please select window'
|
||||
},
|
||||
results: {},
|
||||
}
|
||||
const newObj = document.createElement('input');
|
||||
newObj.setAttribute("id", "testInput");
|
||||
newObj.setAttribute("data-focus-target", "driverSideOptions");
|
||||
document.body.appendChild(newObj);
|
||||
const testInputElement = document.getElementById("testInput");
|
||||
|
||||
//Act
|
||||
vehicleDamage.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "vehicle-damage" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
wrapper.vm.onInvalidSubmit(mockedValidationPayload);
|
||||
await nextTick();
|
||||
const focusedEl = document.activeElement;
|
||||
|
||||
//Assert
|
||||
expect(testInputElement).toBe(focusedEl);
|
||||
});
|
||||
});
|
||||
|
||||
// THE FOLLOWING TEST IS NOT NECESSARILY REQUIRED FOR COVERAGE
|
||||
// BUT KEEP FOR AN EXAMPLE OF A VALIDATION TEST
|
||||
//
|
||||
describe("vehicle-damage.vue", () => {
|
||||
test("when validation rules are set they should validate correctly", async () => {
|
||||
|
||||
//Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
//Act
|
||||
vehicleDamage.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "vehicle-damage" } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
const testNull = validate( "", "replace-options-required");
|
||||
const testString = validate( "sldfj", "replace-options-required");
|
||||
await flushPromises();
|
||||
|
||||
//Assert
|
||||
testNull.then(function(data) {
|
||||
expect(data.valid).toEqual(false);
|
||||
});
|
||||
testString.then(function(data) {
|
||||
expect(data.valid).toEqual(true);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function setupMocks({
|
||||
pageHeaderWidgetHeaderText = {},
|
||||
|
|
@ -762,6 +855,11 @@ function setupMocks({
|
|||
router: {
|
||||
navigate: jest.fn(),
|
||||
},
|
||||
store: {
|
||||
getters: {
|
||||
vehicle: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}) {
|
||||
//Mock api responses
|
||||
|
|
@ -826,6 +924,7 @@ function setupMocks({
|
|||
|
||||
replaceOptionsQuestion.methods = {
|
||||
initializeComponent: jest.fn(),
|
||||
updateSelectedValues: jest.fn(),
|
||||
};
|
||||
|
||||
funnelFooter.methods = {
|
||||
|
|
@ -833,7 +932,9 @@ function setupMocks({
|
|||
}
|
||||
|
||||
const mountOptions = getMountOptions(mountOptionsMockData);
|
||||
const wrapper = shallowMount(vehicleDamage, mountOptions);
|
||||
mountOptions['attachTo'] = document.body; // append wrapper to document.body to test DOM methods
|
||||
|
||||
const wrapper = mount(vehicleDamage, mountOptions);
|
||||
|
||||
const funnelHeaderWrapper = wrapper.findComponent({ name: "funnelHeader" });
|
||||
funnelHeaderWrapper.vm.initializeComponent =
|
||||
|
|
@ -847,36 +948,25 @@ function setupMocks({
|
|||
sideDoorOptionsWrapper.vm.initializeComponent =
|
||||
sideDoorOptions.methods.initializeComponent;
|
||||
|
||||
const windshieldOptionsWrapper = wrapper.findComponent({
|
||||
name: "windshieldOptions",
|
||||
});
|
||||
|
||||
const windshieldOptionsWrapper = wrapper.findComponent({ name: "windshieldOptions" });
|
||||
windshieldOptionsWrapper.vm.initializeComponent =
|
||||
windshieldOptions.methods.initializeComponent;
|
||||
|
||||
const funnelSubHeaderWrapper = wrapper.findComponent({
|
||||
name: "funnelSubHeader",
|
||||
});
|
||||
const funnelSubHeaderWrapper = wrapper.findComponent({ name: "funnelSubHeader" });
|
||||
funnelSubHeaderWrapper.vm.initializeComponent =
|
||||
funnelSubHeader.methods.initializeComponent;
|
||||
|
||||
const backGlassOptionsWrapper = wrapper.findComponent({
|
||||
name: "replaceOptionsQuestion",
|
||||
});
|
||||
const backGlassOptionsWrapper = wrapper.findComponent({ name: "replaceOptionsQuestion" });
|
||||
backGlassOptionsWrapper.vm.initializeComponent =
|
||||
replaceOptionsQuestion.methods.initializeComponent;
|
||||
|
||||
const damageLocationQuestionWrapper = wrapper.findComponent({
|
||||
name: "damageLocationQuestion",
|
||||
});
|
||||
const damageLocationQuestionWrapper = wrapper.findComponent({ name: "damageLocationQuestion" });
|
||||
damageLocationQuestionWrapper.vm.initializeComponent =
|
||||
damageLocationQuestion.methods.initializeComponent;
|
||||
|
||||
const funnelFooterWrapper = wrapper.findComponent({
|
||||
name: "funnelFooter",
|
||||
});
|
||||
|
||||
funnelFooterWrapper.vm.initializeComponent = funnelFooter.methods.initializeComponent;
|
||||
const funnelFooterWrapper = wrapper.findComponent({ name: "funnelFooter" });
|
||||
funnelFooterWrapper.vm.initializeComponent =
|
||||
funnelFooter.methods.initializeComponent;
|
||||
|
||||
return { wrapper, apiPromise };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,29 +3,52 @@
|
|||
<funnelHeader ref="funnelHeader" />
|
||||
<vehicleBanner ref="vehicleBanner" :displayGenericVehicleImage=false />
|
||||
<funnelSubHeader ref="funnelSubHeader" />
|
||||
<damageLocationQuestion
|
||||
ref="damageLocation"
|
||||
v-model="selectedDamageLocations"
|
||||
groupName="DamageLocationQuestion"
|
||||
/>
|
||||
<windshieldOptions
|
||||
ref="windshieldOptions"
|
||||
v-model="selectedWindshieldOptions"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<sideDoorOptions
|
||||
ref="sideDoorOptions"
|
||||
groupName="SideDoorSideQuestion"
|
||||
v-model="sideDoorOptionsData"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="backGlassOptions"
|
||||
:isAvailable="isRearWindowDamageLocation"
|
||||
v-model="selectedRearReplaceOptions"
|
||||
groupName="BackGlassReplaceOptionsQuestion"
|
||||
/>
|
||||
<funnelFooter ref="funnelFooter" @back-clicked="backButtonAction" @ForwardClicked="forwardButtonAction" />
|
||||
<Form
|
||||
@submit="onSubmit"
|
||||
@invalid-submit="onInvalidSubmit"
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
>
|
||||
<damageLocationQuestion
|
||||
ref="damageLocation"
|
||||
v-model="selectedDamageLocations"
|
||||
groupName="DamageLocationQuestion"
|
||||
/>
|
||||
<windshieldOptions
|
||||
ref="windshieldOptions"
|
||||
v-model="selectedWindshieldOptions"
|
||||
:hasRepairReplaceConflict="hasRepairReplaceConflict"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<alert
|
||||
class="my-3"
|
||||
v-show="hasRepairReplaceConflict"
|
||||
alertClass="alert-danger"
|
||||
alertHeadline="You'll need to schedule separate appointments"
|
||||
alertCopy="Vehicle service requiring both glass repair and replacement must be scheduled separately, as they're performed by different technicians. Continue scheduling your first service now, and then come back to schedule the second service."
|
||||
:isDismissible="false"
|
||||
/>
|
||||
<sideDoorOptions
|
||||
ref="sideDoorOptions"
|
||||
groupName="SideDoorSideQuestion"
|
||||
v-model="sideDoorOptionsData"
|
||||
v-show="!hasRepairReplaceConflict"
|
||||
:selectedDamageLocations="selectedDamageLocations"
|
||||
/>
|
||||
<replaceOptionsQuestion
|
||||
ref="backGlassOptions"
|
||||
:isAvailable="isRearWindowDamageLocation && !hasRepairReplaceConflict"
|
||||
v-model="selectedRearReplaceOptions"
|
||||
groupName="BackGlassReplaceOptionsQuestion"
|
||||
validationRules="replace-options-required"
|
||||
/>
|
||||
<funnel-footer
|
||||
ref="funnelFooter"
|
||||
:isDisabled="!meta.valid"
|
||||
@back-clicked="backButtonAction"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
/>
|
||||
</Form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -39,6 +62,7 @@ import sideDoorOptions from "@/layouts/vehicle-damage/side-door-options/side-doo
|
|||
import damageLocationQuestion from "@/layouts/vehicle-damage/damage-location-question/damage-location-question";
|
||||
import windshieldOptions from "@/layouts/vehicle-damage/windshield-options/windshield-options";
|
||||
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
|
||||
// Supporting files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
|
|
@ -46,9 +70,14 @@ import { settleAllPromises } from "@/helpers/layout-helper";
|
|||
import { storeActions } from "@/constants/store-actions";
|
||||
import store from "@/store";
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
||||
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED));
|
||||
|
||||
export default {
|
||||
name: "vehicle-damage",
|
||||
|
|
@ -119,7 +148,7 @@ export default {
|
|||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
return store.getters.vehicle.carId !== null;
|
||||
},
|
||||
},
|
||||
resetDependentState() {
|
||||
store.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
||||
},
|
||||
|
|
@ -130,6 +159,18 @@ export default {
|
|||
this.$route
|
||||
);
|
||||
},
|
||||
onSubmit() {}, // DO NOT REMOVE; needed to prevent default form submit behavior
|
||||
onInvalidSubmit({ values, errors, results }) {
|
||||
// identify the first error field and put focus on it
|
||||
// get error names array
|
||||
const errorNames = errors ? Object.keys(errors) : [];
|
||||
const firstErrorEl = errorNames[0];
|
||||
if (firstErrorEl) {
|
||||
const qsString = "[data-focus-target='" + firstErrorEl + "']";
|
||||
const el = document.querySelector(qsString);
|
||||
el && el.focus();
|
||||
}
|
||||
},
|
||||
|
||||
getDamageLocationsFromStore() {
|
||||
var glassSelections = [];
|
||||
|
|
@ -304,7 +345,7 @@ export default {
|
|||
return selectedGlassToReplace;
|
||||
},
|
||||
},
|
||||
computed:{
|
||||
computed: {
|
||||
isWindshieldDamageLocation() {
|
||||
return this.selectedDamageLocations.some(selectedDamages =>
|
||||
{
|
||||
|
|
@ -326,7 +367,7 @@ export default {
|
|||
isWindshieldRepair() {
|
||||
if (!this.isWindshieldDamageLocation) return false;
|
||||
|
||||
return this.selectedWindshieldOptions.selectedWindshieldDamageType.some(selectedDamageType =>
|
||||
return this.selectedWindshieldOptions.selectedWindshieldDamageType && this.selectedWindshieldOptions.selectedWindshieldDamageType.some(selectedDamageType =>
|
||||
{
|
||||
return selectedDamageType.toUpperCase() === "REPAIR";
|
||||
});
|
||||
|
|
@ -346,7 +387,10 @@ export default {
|
|||
{
|
||||
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
|
||||
});
|
||||
}
|
||||
},
|
||||
hasRepairReplaceConflict() {
|
||||
return this.isWindshieldDamageLocation && this.selectedDamageLocations.length > 1 && this.isWindshieldRepair;
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
|
|
@ -358,6 +402,8 @@ export default {
|
|||
damageLocationQuestion,
|
||||
windshieldOptions,
|
||||
replaceOptionsQuestion,
|
||||
Form,
|
||||
alert,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
buttonType="listButtonHorizontal"
|
||||
useTextForValue
|
||||
v-model="selectedChipCountValues"
|
||||
:validationRules="validationRules"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
|
|
@ -28,12 +29,19 @@ export default ({
|
|||
modelValue: Array,
|
||||
groupName: String,
|
||||
isAvailable: Boolean,
|
||||
validationRules: String,
|
||||
},
|
||||
methods: {
|
||||
initializeComponent(cmsContent){
|
||||
this.questionText = cmsContent.QuestionText;
|
||||
this.answersFromCms = cmsContent.Answers;
|
||||
}
|
||||
},
|
||||
updateSelectedValues() {
|
||||
// UPDATE SELECTEDVALUES IF ONLY ONE ANSWER
|
||||
if(Array.isArray(this.answersToDisplay) && this.answersToDisplay.length === 1 && this.selectedValues) {
|
||||
this.selectedValues = [this.answersToDisplay[0].Name];
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
selectedChipCountValues: {
|
||||
|
|
@ -45,6 +53,12 @@ export default ({
|
|||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
isAvailable(val) {
|
||||
// CHECK TO UPDATE SELECTED VALUES WHEN ISAVAILABLE IS TRUE
|
||||
val && this.updateSelectedValues();
|
||||
}
|
||||
},
|
||||
components: {
|
||||
buttonQuestion,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
:groupName="groupName"
|
||||
buttonType="listCard"
|
||||
v-model="selectedValues"
|
||||
:suppressError="suppressError"
|
||||
:validationRules="validationRules"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
|
|
@ -14,24 +16,7 @@
|
|||
|
||||
<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;
|
||||
// });
|
||||
import store from "@/store";
|
||||
|
||||
export default ({
|
||||
name: "windshieldDamageTypeQuestion",
|
||||
|
|
@ -46,12 +31,13 @@ export default ({
|
|||
groupName: String,
|
||||
isAvailable: Boolean,
|
||||
suppressError: Boolean,
|
||||
validationRules: String,
|
||||
},
|
||||
methods: {
|
||||
initializeComponent(cmsContent){
|
||||
this.questionText = cmsContent.QuestionText;
|
||||
this.answersFromCms = cmsContent.Answers;
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
selectedValues: {
|
||||
|
|
|
|||
|
|
@ -2,20 +2,23 @@
|
|||
<div class="windshield-options">
|
||||
<windshieldDamageTypeQuestion ref="windshieldDamageTypeQuestion"
|
||||
:isAvailable=isWindshieldDamageLocation
|
||||
:suppressError="suppressError"
|
||||
:suppressError="hasRepairReplaceConflict"
|
||||
groupName="WindshieldDamageTypeQuestion"
|
||||
v-model="selectedWindshieldDamageTypeValues"
|
||||
v-model="selectedWindshieldDamageTypeValues"
|
||||
validationRules="windshield-damage-type-required|checkForRepairAndReplace:@DamageLocationQuestion"
|
||||
/>
|
||||
<windshieldChipCountQuestion ref="windshieldChipCountQuestion"
|
||||
:isAvailable=isRepairOptionSelected
|
||||
:isAvailable="isRepairOptionSelected && !hasRepairReplaceConflict"
|
||||
groupName="WindshieldChipCountQuestion"
|
||||
v-model="selectedWindshieldChipCountValues"
|
||||
v-model="selectedWindshieldChipCountValues"
|
||||
validationRules="windshield-chip-count-required"
|
||||
/>
|
||||
<replaceOptionsQuestion ref="replaceOptionsQuestion"
|
||||
:isAvailable=isReplaceOptionSelected
|
||||
isMultiSelect
|
||||
groupName="WindshieldReplaceOptions"
|
||||
v-model="selectedWindshieldReplaceOptionsValues"
|
||||
validationRules="windshield-replace-options-required"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -24,15 +27,29 @@
|
|||
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";
|
||||
import { defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("windshield-damage-type-required", required(errorMessages.WINDSHIELD_DAMAGE_TYPE_REQUIRED));
|
||||
defineRule("windshield-chip-count-required", required(errorMessages.WINDSHIELD_CHIP_COUNT_REQUIRED));
|
||||
defineRule("windshield-replace-options-required", required(errorMessages.WINSHIELD_REPLACE_OPTIONS_REQUIRED));
|
||||
|
||||
defineRule("checkForRepairAndReplace", (value, [other]) => {
|
||||
if (value.toString().toUpperCase().includes("REPAIR") && other.toString().toUpperCase().includes("WINDSHIELD") && other.length > 1) {
|
||||
return "checkForRepairAndReplace error"
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
export default ({
|
||||
name: "windshieldOptions",
|
||||
|
||||
props: {
|
||||
modelValue: Array,
|
||||
selectedDamageLocations: Array,
|
||||
selectedChipCount: Array,
|
||||
selectedReplaceOptions: Array,
|
||||
suppressError: Boolean
|
||||
hasRepairReplaceConflict: Boolean
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -186,12 +186,7 @@ describe("vehicle-style.vue", () => {
|
|||
store: {
|
||||
commit: jest.fn(),
|
||||
getters: {
|
||||
vehicle: {
|
||||
year: 2020,
|
||||
make: "Honda",
|
||||
model: "Civic",
|
||||
style: "2 Door",
|
||||
},
|
||||
vehicle: {},
|
||||
},
|
||||
},
|
||||
actionList: [
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
<template>
|
||||
<div
|
||||
class="list-group list-button-horizontal d-flex flex-column w-100 mb-2"
|
||||
:class="hasError ? 'has-error' : ''"
|
||||
@mouseup="handleClick(value)"
|
||||
@keyup.space="handleClick(value)"
|
||||
:class="[errors.length > 0 ? 'has-error' : '', hasError ? 'has-error' : '']"
|
||||
>
|
||||
<input
|
||||
:type="isMultiSelect ? 'checkbox' : 'radio'"
|
||||
|
|
@ -12,6 +10,7 @@
|
|||
:value="value"
|
||||
:aria-required="isRequired"
|
||||
:data-focus-target="groupName"
|
||||
@click="handleClick(value)"
|
||||
v-model="checkValue"
|
||||
@change="!selectingInitiatesLoad ? handleCheckChange() : ''"
|
||||
/>
|
||||
|
|
@ -46,7 +45,6 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { toRefs } from "vue";
|
||||
import { useField } from "vee-validate";
|
||||
import loader from "@/ux-components/loader/loader";
|
||||
|
||||
|
|
@ -69,6 +67,7 @@ export default {
|
|||
type: String,
|
||||
default: "",
|
||||
},
|
||||
validationRules: String,
|
||||
selectedValues: [Array, String],
|
||||
hasError: Boolean,
|
||||
},
|
||||
|
|
@ -105,20 +104,25 @@ export default {
|
|||
loader,
|
||||
},
|
||||
setup(props) {
|
||||
const { groupName, value } = toRefs(props);
|
||||
const inputType = props.isMultiSelect ? "checkbox" : "radio";
|
||||
const { checked, handleChange, errorMessage } = useField(
|
||||
groupName,
|
||||
undefined,
|
||||
{
|
||||
type: inputType,
|
||||
checkedValue: value,
|
||||
}
|
||||
);
|
||||
const fieldOptions = {
|
||||
type: inputType,
|
||||
checkedValue: props.value,
|
||||
};
|
||||
|
||||
if (Array.isArray(props.selectedValues) && props.selectedValues.length == 1) {
|
||||
fieldOptions['initialValue'] = fieldOptions.checkedValue;
|
||||
}
|
||||
const {
|
||||
checked,
|
||||
handleChange,
|
||||
errors,
|
||||
} = useField(props.groupName, props.validationRules, fieldOptions);
|
||||
|
||||
return {
|
||||
checked,
|
||||
handleChange,
|
||||
errorMessage,
|
||||
errors,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
<template>
|
||||
<div
|
||||
class="list-group list-button d-flex flex-column w-100 mb-2"
|
||||
:class="hasError ? 'has-error' : ''"
|
||||
@mouseup="handleClick(value)"
|
||||
@keyup.space="handleClick(value)"
|
||||
:class="[errors.length > 0 ? 'has-error' : '', hasError ? 'has-error' : '']"
|
||||
>
|
||||
<input
|
||||
:type="isMultiSelect ? 'checkbox' : 'radio'"
|
||||
|
|
@ -12,6 +10,7 @@
|
|||
:value="value"
|
||||
:aria-required="isRequired"
|
||||
:data-focus-target="groupName"
|
||||
@click="handleClick(value)"
|
||||
v-model="checkValue"
|
||||
@change="!selectingInitiatesLoad ? handleCheckChange() : ''"
|
||||
>
|
||||
|
|
@ -49,9 +48,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { toRefs } from "vue";
|
||||
import { useField } from "vee-validate";
|
||||
import loader from "@/ux-components/loader/loader";
|
||||
|
||||
export default {
|
||||
name: "listButton",
|
||||
props: {
|
||||
|
|
@ -71,6 +70,7 @@ export default {
|
|||
type: [String, Number],
|
||||
default: "",
|
||||
},
|
||||
validationRules: String,
|
||||
selectedValues: [Array, String],
|
||||
hasError: Boolean,
|
||||
},
|
||||
|
|
@ -107,20 +107,25 @@ export default {
|
|||
loader,
|
||||
},
|
||||
setup(props) {
|
||||
const { groupName, value } = toRefs(props);
|
||||
const inputType = props.isMultiSelect ? "checkbox" : "radio";
|
||||
const { checked, handleChange, errorMessage } = useField(
|
||||
groupName,
|
||||
undefined,
|
||||
{
|
||||
type: inputType,
|
||||
checkedValue: value,
|
||||
}
|
||||
);
|
||||
const fieldOptions = {
|
||||
type: inputType,
|
||||
checkedValue: props.value,
|
||||
};
|
||||
|
||||
if (Array.isArray(props.selectedValues) && props.selectedValues.length == 1) {
|
||||
fieldOptions['initialValue'] = fieldOptions.checkedValue;
|
||||
}
|
||||
const {
|
||||
checked,
|
||||
handleChange,
|
||||
errors,
|
||||
} = useField(props.groupName, props.validationRules, fieldOptions);
|
||||
|
||||
return {
|
||||
checked,
|
||||
handleChange,
|
||||
errorMessage,
|
||||
errors,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ describe("list-card.vue", () => {
|
|||
});
|
||||
wrapper.vm.handleCheckChange();
|
||||
// Assert
|
||||
expect(wrapper.emitted()["isCheckedChanged"][0]).toEqual([{value: "List Card Checkbox", checkValue: Boolean, buttonId: 'list-card-id'}]);
|
||||
expect(wrapper.emitted()["isCheckedChanged"][0]).toEqual([{value: "List Card Checkbox", checkValue: [Boolean, String], buttonId: 'list-card-id'}]);
|
||||
});
|
||||
|
||||
it("Should set checkValue data if selectedButtonIDs has value(s)", async () => {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
:data-focus-target="groupName"
|
||||
@click="handleChange(value)"
|
||||
v-model="checkValue"
|
||||
@change="handleCheckChange()"
|
||||
@change="handleCheckChange(value)"
|
||||
/>
|
||||
<label
|
||||
:for="buttonID"
|
||||
|
|
@ -83,8 +83,8 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
checkValue: Boolean,
|
||||
};
|
||||
checkValue: [Boolean, String],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (Array.isArray(this.selectedValues)) {
|
||||
|
|
@ -131,14 +131,21 @@ export default {
|
|||
},
|
||||
setup(props) {
|
||||
const inputType = props.isMultiSelect ? "checkbox" : "radio";
|
||||
const {
|
||||
value: inputValue,
|
||||
handleChange,
|
||||
errors,
|
||||
} = useField(props.groupName, props.validationRules, {
|
||||
|
||||
const fieldOptions = {
|
||||
type: inputType,
|
||||
checkedValue: props.value,
|
||||
});
|
||||
};
|
||||
|
||||
if (Array.isArray(props.selectedValues) && props.selectedValues.length == 1) {
|
||||
fieldOptions['initialValue'] = fieldOptions.checkedValue;
|
||||
}
|
||||
|
||||
const {
|
||||
handleChange,
|
||||
errors,
|
||||
} = useField(props.groupName, props.validationRules, fieldOptions);
|
||||
|
||||
return {
|
||||
handleChange,
|
||||
errors,
|
||||
|
|
|
|||
Loading…
Reference in a new issue