Merge remote-tracking branch 'origin/feature/CSR-762' into feature/CSR-731
This commit is contained in:
commit
65cf2d3b84
52 changed files with 2559 additions and 1649 deletions
|
|
@ -28,8 +28,7 @@ module.exports = {
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
// TODO KO
|
statements: 80,
|
||||||
statements: 55,
|
|
||||||
// Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90
|
// Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
35
src/App.vue
35
src/App.vue
|
|
@ -1,16 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<transition :duration="{ enter: 200, leave: 200 }" name="route-fade" mode="out-in">
|
<transition
|
||||||
<!-- The above durations should be kept in sync with the global css class "fade-on-route-transition" -->
|
:duration="{ enter: 200, leave: 200 }"
|
||||||
<component :is="Component" />
|
name="route-fade"
|
||||||
</transition>
|
mode="out-in">
|
||||||
</router-view>
|
<!-- The above durations should be kept in sync with the global css class "fade-on-route-transition" -->
|
||||||
|
<component :is="Component" @focusin="handleAnyComponentFocus" />
|
||||||
|
</transition>
|
||||||
|
</router-view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { handleAnyComponentFocus } from "@/helpers/button-question-focus-helper"
|
||||||
|
export default {
|
||||||
|
name: "app",
|
||||||
|
methods: {
|
||||||
|
handleAnyComponentFocus: handleAnyComponentFocus
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "./node_modules/bootstrap/scss/bootstrap";
|
@import "./node_modules/bootstrap/scss/bootstrap";
|
||||||
@import "@/styles/common-styles.scss";
|
@import "@/styles/common-styles.scss";
|
||||||
@import "@/styles/common-typography-styles.scss";
|
@import "@/styles/common-typography-styles.scss";
|
||||||
@import "@/styles/common-error-styles.scss";
|
@import "@/styles/common-error-styles.scss";
|
||||||
@import "@/styles/common-animations.scss";
|
@import "@/styles/common-animations.scss";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,736 @@
|
||||||
|
import { shallowMount, mount } from "@vue/test-utils";
|
||||||
|
import { EXPECTATION_FAILED } from "http-status-codes";
|
||||||
|
import inputButtonWrapperMixin from "../../mixins/input-button-wrapper-mixin";
|
||||||
|
import baseInputButton from "./base-input-button";
|
||||||
|
|
||||||
|
// TODO KO
|
||||||
|
describe("baseInputButton.vue", () => {
|
||||||
|
describe("general", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test("isMultiSelect => baseInputButton is a checkbox", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(inputElement.attributes().type).toEqual("checkbox");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test("!isMultiSelect => baseInputButton is a radio button", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(inputElement.attributes().type).toEqual("radio");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// tests in here should be test.each
|
||||||
|
describe("shared", () => {
|
||||||
|
const isMultiSelectOptions = [true, false];
|
||||||
|
test.each(isMultiSelectOptions)("groupName", (isMultiSelect) => {
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "boogly",
|
||||||
|
isMultiSelect: isMultiSelect,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
const inputElementAttributes = inputElement.attributes();
|
||||||
|
expect(inputElementAttributes.name).toEqual("boogly");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("mouse clicks", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test("clicked => correct event and value are emitted", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
value: "X",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
// await wrapper.trigger("mousedown.left");
|
||||||
|
await wrapper.trigger("click");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([
|
||||||
|
"X",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test("clicked => correct event and value are emitted", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
value: "X",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.trigger("mousedown.left");
|
||||||
|
await wrapper.trigger("click");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(
|
||||||
|
"X"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("keyboard navigation and events", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test.todo(
|
||||||
|
"focus on a checkbox => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"blur from a checkbox => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test("change event fired from checkbox => inputButtonClicked is emitted with correct value", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("change");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([
|
||||||
|
"Hi",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("focus and click space on a checkbox => inputButtonClicked is not emitted", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("keypress", { key: "space" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()).not.toHaveProperty(
|
||||||
|
"update:modelValue"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("focus and click enter on a checkbox => inputButtonClicked is emitted with correct value", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("keypress", { key: "enter" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual([
|
||||||
|
"Hi",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test.todo(
|
||||||
|
"focus on a radio button => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"blur from a radio button => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test("focus and click space on a radio button => inputButtonClicked is emitted with correct value", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("keypress", { key: "space" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()).toHaveProperty("update:modelValue");
|
||||||
|
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(
|
||||||
|
"Hi"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("focus and click enter on a radio button => inputButtonClicked is emitted with correct value", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
value: "Hi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await input.trigger("keypress", { key: "enter" });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()).toHaveProperty("update:modelValue");
|
||||||
|
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(
|
||||||
|
"Hi"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("methods", () => {
|
||||||
|
describe("handleEventAction", () => {});
|
||||||
|
|
||||||
|
describe("handleSelectionChange", () => {
|
||||||
|
test.todo("handleChange is called with valueToEmit");
|
||||||
|
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test.todo("modelValue is null => valueToEmit is correct value");
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"modelValue is undefined => valueToEmit is correct value"
|
||||||
|
);
|
||||||
|
test.todo(
|
||||||
|
"modelValue is empty => valueToEmit is correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"modelValue is not empty and does not contain this button's value => valueToEmit is correct value"
|
||||||
|
);
|
||||||
|
test.todo(
|
||||||
|
"modelValue is not empty and does contain this button's value => valueToEmit is correct value"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("handleClick", () => {
|
||||||
|
test.todo("handleSelectChange is also called");
|
||||||
|
|
||||||
|
test.todo("inputButtonClicked is emitted with valueToEmit");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("computed", () => {
|
||||||
|
describe("isChecked", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
const falsyModelValues = [[], null, undefined];
|
||||||
|
test.each(falsyModelValues)(
|
||||||
|
"modelValue is falsy/empty => checkbox isn't checked",
|
||||||
|
(modelValue) => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
modelValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(false);
|
||||||
|
expect(inputElement.element.checked).toBe(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
test("modelValue doesn't contain this button's value => checkbox isn't checked", async () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
modelValue: ["Aaa", "Bbb", "Ccc"],
|
||||||
|
value: "Ddd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(false);
|
||||||
|
expect(inputElement.element.checked).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("modelValue contains this button's value => checkbox is checked", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
modelValue: ["Aaa", "Bbb", "Ddd", "Ccc"],
|
||||||
|
value: "Ddd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(true);
|
||||||
|
expect(inputElement.element.checked).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
const falsyModelValues = ["", null, undefined, []];
|
||||||
|
test.each(falsyModelValues)(
|
||||||
|
"modelValue is falsy/empty => radio button isn't checked",
|
||||||
|
(modelValue) => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
modelValue,
|
||||||
|
value: "Aaa",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(false);
|
||||||
|
expect(inputElement.element.checked).toBe(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
test("modelValue equals this button's value => radio button is checked", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
modelValue: "Ddd",
|
||||||
|
value: "Ddd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(true);
|
||||||
|
expect(inputElement.element.checked).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("modelValue doesn't equal this button's value => radio button isn't checked", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
modelValue: "Aaa",
|
||||||
|
value: "Ddd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.isChecked).toEqual(false);
|
||||||
|
expect(inputElement.element.checked).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("buttonId", () => {
|
||||||
|
test("groupName and value combo yield correct id for input button with string value", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "my test-name",
|
||||||
|
value: "Aaa-BBB CcC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.buttonId).toBe("my-test-name-Aaa-BBB-CcC");
|
||||||
|
expect(inputElement.attributes().id).toBe(
|
||||||
|
"my-test-name-Aaa-BBB-CcC"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("groupName and value combo yield correct id for input button with number value", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "my test-name",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.buttonId).toBe("my-test-name-2");
|
||||||
|
expect(inputElement.attributes().id).toBe("my-test-name-2");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("inputType", () => {
|
||||||
|
test("isMultiSelect is true => inputType is 'checkbox'", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.inputType).toEqual("checkbox");
|
||||||
|
expect(inputElement.attributes().type).toBe("checkbox");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isMultiSelect is false => inputType is 'radio'", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const inputElement = wrapper.find("input");
|
||||||
|
expect(wrapper.vm.inputType).toEqual("radio");
|
||||||
|
expect(inputElement.attributes().type).toBe("radio");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("integration testing", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test("click on both => both are selected", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupBaseInputButtonWrapper({
|
||||||
|
mockData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const buttonWrappers = wrapper.findAllComponents({
|
||||||
|
name: "baseInputButtonWrapper",
|
||||||
|
});
|
||||||
|
const inputButtonOne = buttonWrappers.at(0);
|
||||||
|
const inputButtonTwo = buttonWrappers.at(1);
|
||||||
|
expect(inputButtonOne.vm.isMultiSelect).toBe(true);
|
||||||
|
expect(inputButtonTwo.vm.isMultiSelect).toBe(true);
|
||||||
|
expect(wrapper.vm.value).toEqual([]);
|
||||||
|
|
||||||
|
await inputButtonOne.find("input").trigger("click");
|
||||||
|
await inputButtonTwo.find("input").trigger("click");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.value).toEqual(["value1", "value2"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("click input 1, 2, 1 => only input 2 selected", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupBaseInputButtonWrapper({
|
||||||
|
mockData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const buttonWrappers = wrapper.findAllComponents({
|
||||||
|
name: "baseInputButtonWrapper",
|
||||||
|
});
|
||||||
|
const inputButtonOne = buttonWrappers.at(0);
|
||||||
|
const inputButtonTwo = buttonWrappers.at(1);
|
||||||
|
expect(inputButtonOne.vm.isMultiSelect).toBe(true);
|
||||||
|
expect(inputButtonTwo.vm.isMultiSelect).toBe(true);
|
||||||
|
expect(wrapper.vm.value).toEqual([]);
|
||||||
|
|
||||||
|
await inputButtonOne.find("input").trigger("click");
|
||||||
|
await inputButtonTwo.find("input").trigger("click");
|
||||||
|
await inputButtonOne.find("input").trigger("click");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.value).toEqual(["value2"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultCheckedCases = [
|
||||||
|
[["value2"], false, true],
|
||||||
|
[["value1", "value2"], true, true],
|
||||||
|
[["value1"], true, false],
|
||||||
|
[[], false, false]
|
||||||
|
]
|
||||||
|
test.each(defaultCheckedCases)("initial value is %s => correct input buttons are selected", async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupBaseInputButtonWrapper({
|
||||||
|
mockData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
initialValue: modelValue
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const buttonWrappers = wrapper.findAllComponents({
|
||||||
|
name: "baseInputButtonWrapper",
|
||||||
|
});
|
||||||
|
const inputs = wrapper.findAll("input");
|
||||||
|
const inputButtonOne = buttonWrappers.at(0);
|
||||||
|
const inputButtonTwo = buttonWrappers.at(1);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(inputButtonOne.vm.isMultiSelect).toBe(true);
|
||||||
|
expect(inputButtonTwo.vm.isMultiSelect).toBe(true);
|
||||||
|
expect(inputs[0].element.checked).toBe(isInputButtonOneChecked);
|
||||||
|
expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked);
|
||||||
|
expect(wrapper.vm.value).toEqual(modelValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test("click on both => last clicked is selected", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupBaseInputButtonWrapper({
|
||||||
|
mockData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const buttonWrappers = wrapper.findAllComponents({
|
||||||
|
name: "baseInputButtonWrapper",
|
||||||
|
});
|
||||||
|
const inputButtonOne = buttonWrappers.at(0);
|
||||||
|
const inputButtonTwo = buttonWrappers.at(1);
|
||||||
|
expect(inputButtonOne.vm.isMultiSelect).toBe(false);
|
||||||
|
expect(inputButtonTwo.vm.isMultiSelect).toBe(false);
|
||||||
|
expect(wrapper.vm.value).toEqual("");
|
||||||
|
|
||||||
|
await inputButtonOne.find("input").trigger("click");
|
||||||
|
await inputButtonTwo.find("input").trigger("click");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.value).toEqual("value2");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("click input 1, 2, 1 => input 1 is selected", async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupBaseInputButtonWrapper({
|
||||||
|
mockData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const buttonWrappers = wrapper.findAllComponents({
|
||||||
|
name: "baseInputButtonWrapper",
|
||||||
|
});
|
||||||
|
const inputButtonOne = buttonWrappers.at(0);
|
||||||
|
const inputButtonTwo = buttonWrappers.at(1);
|
||||||
|
expect(inputButtonOne.vm.isMultiSelect).toBe(false);
|
||||||
|
expect(inputButtonTwo.vm.isMultiSelect).toBe(false);
|
||||||
|
expect(wrapper.vm.value).toEqual("");
|
||||||
|
|
||||||
|
await inputButtonOne.find("input").trigger("click");
|
||||||
|
await inputButtonTwo.find("input").trigger("click");
|
||||||
|
await inputButtonOne.find("input").trigger("click");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.value).toEqual("value1");
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultCheckedCases = [
|
||||||
|
["", false, false],
|
||||||
|
["value1", true, false],
|
||||||
|
["value2", false, true],
|
||||||
|
[[], false, false]
|
||||||
|
]
|
||||||
|
test.each(defaultCheckedCases)("initial value is %s => correct input buttons are selected", async (modelValue, isInputButtonOneChecked, isInputButtonTwoChecked) => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = setupBaseInputButtonWrapper({
|
||||||
|
mockData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
initialValue: modelValue
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const buttonWrappers = wrapper.findAllComponents({
|
||||||
|
name: "baseInputButtonWrapper",
|
||||||
|
});
|
||||||
|
const inputs = wrapper.findAll("input");
|
||||||
|
const inputButtonOne = buttonWrappers.at(0);
|
||||||
|
const inputButtonTwo = buttonWrappers.at(1);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(inputButtonOne.vm.isMultiSelect).toBe(false);
|
||||||
|
expect(inputButtonTwo.vm.isMultiSelect).toBe(false);
|
||||||
|
expect(inputs[0].element.checked).toBe(isInputButtonOneChecked);
|
||||||
|
expect(inputs[1].element.checked).toBe(isInputButtonTwoChecked);
|
||||||
|
expect(wrapper.vm.value).toEqual(modelValue);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupMocks({ mockData = {}, shouldShallowMount = true }) {
|
||||||
|
const baseInputButtonWrapper = {
|
||||||
|
components: { baseInputButton },
|
||||||
|
template: '<baseInputButton v-model="myValue" />',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
myValue: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mountMockData = {
|
||||||
|
...mockData,
|
||||||
|
propsData: {
|
||||||
|
// to get rid of some annoying warnings
|
||||||
|
groupName: "groupName",
|
||||||
|
modelValue: mockData.propsData?.isMultiSelect ? [] : "",
|
||||||
|
value: "5",
|
||||||
|
setLastValuePushedToGa: () => {},
|
||||||
|
// should override the above if they exist
|
||||||
|
...mockData.propsData,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = shouldShallowMount
|
||||||
|
? shallowMount(baseInputButton, mountMockData)
|
||||||
|
: mount(baseInputButton, mountMockData);
|
||||||
|
|
||||||
|
wrapper.vm.pushEventToGA = jest.fn();
|
||||||
|
wrapper.vm.$route = {
|
||||||
|
query: {},
|
||||||
|
};
|
||||||
|
wrapper.vm.GaActions = {};
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupBaseInputButtonWrapper({ mockData = {} }) {
|
||||||
|
const originalData = baseInputButton.data();
|
||||||
|
baseInputButton.data = () => {
|
||||||
|
return {
|
||||||
|
...originalData,
|
||||||
|
// $route: {
|
||||||
|
// query: {
|
||||||
|
// fmgPage: "myPage",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// console.log({
|
||||||
|
// test: baseInputButton.vm.$route
|
||||||
|
// })
|
||||||
|
baseInputButton.methods.pushClickEventToGA = jest.fn();
|
||||||
|
|
||||||
|
const baseInputButtonWrapper = {
|
||||||
|
name: "baseInputButtonWrapper",
|
||||||
|
components: { baseInputButton },
|
||||||
|
template:
|
||||||
|
'<div><baseInputButton v-bind="$props" v-model="selectedValue" /></div>',
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
};
|
||||||
|
|
||||||
|
let parentComponentTemplate = `<div>`;
|
||||||
|
parentComponentTemplate += `<baseInputButtonWrapper v-model="value" groupName="myGroupName" :isMultiSelect="${mockData.isMultiSelect}" value="value1" />`;
|
||||||
|
parentComponentTemplate += `<baseInputButtonWrapper v-model="value" groupName="myGroupName" :isMultiSelect="${mockData.isMultiSelect}" value="value2" />`;
|
||||||
|
parentComponentTemplate += `</div>`;
|
||||||
|
const wrapper = mount(
|
||||||
|
{
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value:
|
||||||
|
mockData.initialValue ??
|
||||||
|
(mockData.isMultiSelect ? [] : ""),
|
||||||
|
$route: {
|
||||||
|
query: {
|
||||||
|
fmgPage: "myPage",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: parentComponentTemplate,
|
||||||
|
components: { baseInputButtonWrapper },
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
<label
|
<label
|
||||||
:class="[buttonWrapperClasses, { 'has-error': errors.length > 0 }]"
|
:class="[buttonWrapperClasses, { 'has-error': errors.length > 0 }]"
|
||||||
:for="buttonId"
|
:for="buttonId"
|
||||||
@mousedown.left="handleEventAction('click', $event)"
|
@focusin="handleFocus"
|
||||||
@keyup="handleKeyboardNavigation">
|
@focusout="handleBlur"
|
||||||
|
@mousedown.left="handleEventAction('click', $event)">
|
||||||
<input
|
<input
|
||||||
:type="inputType"
|
:type="inputType"
|
||||||
:id="buttonId"
|
:id="buttonId"
|
||||||
|
|
@ -13,8 +14,8 @@
|
||||||
:aria-required="isRequired"
|
:aria-required="isRequired"
|
||||||
:value="value"
|
:value="value"
|
||||||
:checked="isChecked"
|
:checked="isChecked"
|
||||||
@blur="handleBlur"
|
@keypress.space="handleEventAction('space', $event)"
|
||||||
@keypress.enter="handleEventAction('keypressSubmit', $event)"
|
@keypress.enter="handleEventAction('enter', $event)"
|
||||||
@change="handleEventAction('change', $event)" />
|
@change="handleEventAction('change', $event)" />
|
||||||
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
@ -22,43 +23,18 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
|
||||||
import { useField } from "vee-validate";
|
import { useField } from "vee-validate";
|
||||||
import { toRef } from "vue";
|
import { toRef } from "vue";
|
||||||
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
import { handleButtonComponentFocus, handleInputComponentBlur } from "@/helpers/button-question-focus-helper";
|
||||||
|
import { inputButtonProps } from "@/common-components/base-input-button/button-functionality-props";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "base-input-button",
|
name: "base-input-button",
|
||||||
emits: ["change"],
|
|
||||||
model: {
|
|
||||||
prop: "modelValue",
|
|
||||||
event: "change",
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
value: {
|
...inputButtonProps,
|
||||||
type: [String, Number],
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
modelValue: {
|
|
||||||
type: [Array, String, Number],
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
isMultiSelect: Boolean,
|
|
||||||
groupName: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
validationRules: {
|
|
||||||
type: String,
|
|
||||||
default: "",
|
|
||||||
},
|
|
||||||
buttonWrapperClasses: [String, Array, Object],
|
buttonWrapperClasses: [String, Array, Object],
|
||||||
inputClasses: [String, Array, Object],
|
inputClasses: [String, Array, Object],
|
||||||
valueToLogType: String,
|
|
||||||
selectOnKeypress: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
isRequired: Boolean,
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -72,32 +48,34 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleEventAction(eventType, e) {
|
handleEventAction(eventType, e) {
|
||||||
const eventTypes = {
|
// console.log({
|
||||||
CHANGE: "change",
|
// eventType,
|
||||||
KEYPRESS_SUBMIT: "keypressSubmit",
|
// e
|
||||||
CLICK: "click",
|
// })
|
||||||
};
|
|
||||||
|
|
||||||
if (this.isMultiSelect) {
|
if (this.isMultiSelect) {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case eventTypes.KEYPRESS_SUBMIT:
|
case this.eventTypes.ENTER:
|
||||||
case eventTypes.CHANGE:
|
case this.eventTypes.CHANGE:
|
||||||
this.handleClick(e);
|
this.handleClick(e);
|
||||||
window.lastFocusedInputGroup = this.groupName;
|
this.handlePushClickEventToGACheck(
|
||||||
this.pushClickEventToGA();
|
this.eventTypes.CLICK
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case eventTypes.CLICK:
|
case this.eventTypes.CLICK:
|
||||||
case eventTypes.KEYPRESS_SUBMIT:
|
case this.eventTypes.ENTER:
|
||||||
|
case this.eventTypes.SPACE:
|
||||||
this.handleClick(e);
|
this.handleClick(e);
|
||||||
this.test();
|
this.handlePushClickEventToGACheck(
|
||||||
|
this.eventTypes.CLICK
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case eventTypes.CHANGE:
|
case this.eventTypes.CHANGE:
|
||||||
this.selectOnKeypress
|
this.selectingInitiatesLoad
|
||||||
? this.handleClick(e)
|
? this.handleSelectionChange(e)
|
||||||
: this.handleSelectionChange(e);
|
: this.handleClick(e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -119,21 +97,40 @@ export default {
|
||||||
this.valueToEmit = this.value;
|
this.valueToEmit = this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.currentlySelectedValues =
|
|
||||||
window.currentlySelectedValues ?? {};
|
|
||||||
window.currentlySelectedValues[this.groupName] = this.value;
|
|
||||||
this.handleChange(this.valueToEmit);
|
this.handleChange(this.valueToEmit);
|
||||||
},
|
},
|
||||||
handleClick(e) {
|
handleClick(e) {
|
||||||
this.handleSelectionChange(e);
|
this.handleSelectionChange(e);
|
||||||
this.$emit("buttonClicked", this.valueToEmit);
|
this.$emit("update:modelValue", this.valueToEmit);
|
||||||
|
},
|
||||||
|
handleFocus() {
|
||||||
|
handleButtonComponentFocus({
|
||||||
|
groupName: this.groupName,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleBlur() {
|
||||||
|
handleInputComponentBlur({
|
||||||
|
groupName: this.groupName,
|
||||||
|
onButtonQuestionLostFocusCallback: this.handlePushClickEventToGACheck,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handlePushClickEventToGACheck(source) {
|
||||||
|
if (source === this.eventTypes.CLICK) {
|
||||||
|
this.pushClickEventToGA();
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
this.valueToEmit !== null &&
|
||||||
|
!this.isValueSelectedOnClick &&
|
||||||
|
this.isChecked &&
|
||||||
|
this.lastValuePushedToGa != this.value
|
||||||
|
) {
|
||||||
|
this.pushClickEventToGA();
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pushClickEventToGA(value) {
|
pushClickEventToGA(value) {
|
||||||
window.firedGaClickEventValues =
|
console.log("PUSHHH")
|
||||||
window.firedGaClickEventValues ?? {};
|
console.log(this.$route)
|
||||||
window.firedGaClickEventValues[window.lastFocusedInputGroup] =
|
|
||||||
value ?? this.value;
|
|
||||||
|
|
||||||
this.pushEventToGA(
|
this.pushEventToGA(
|
||||||
this.$route.query[queryStrings.FMG_PAGE],
|
this.$route.query[queryStrings.FMG_PAGE],
|
||||||
this.GaActions.CLICKED,
|
this.GaActions.CLICKED,
|
||||||
|
|
@ -141,88 +138,38 @@ export default {
|
||||||
true,
|
true,
|
||||||
this.valueToLogType
|
this.valueToLogType
|
||||||
);
|
);
|
||||||
},
|
|
||||||
handleBlur() {
|
|
||||||
window.lastFocusedInputGroup = this.groupName;
|
|
||||||
window.wasLastFocusedInputMultiselect = this.isMultiSelect;
|
|
||||||
},
|
|
||||||
handleKeyboardNavigation(key) {
|
|
||||||
this.test(key);
|
|
||||||
},
|
|
||||||
test(event) {
|
|
||||||
window.firedGaClickEventValues =
|
|
||||||
window.firedGaClickEventValues ?? {};
|
|
||||||
window.currentlySelectedValues =
|
|
||||||
window.currentlySelectedValues ?? {};
|
|
||||||
|
|
||||||
const keyCode = event?.code;
|
this.setLastValuePushedToGa(this.value);
|
||||||
// Keyboard navigation
|
|
||||||
if (keyCode) {
|
|
||||||
if (
|
|
||||||
window.currentlySelectedValues &&
|
|
||||||
window.firedGaClickEventValues &&
|
|
||||||
window.lastFocusedInputGroup &&
|
|
||||||
!window.wasLastFocusedInputMultiselect &&
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
] &&
|
|
||||||
window.firedGaClickEventValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
] !=
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
]
|
|
||||||
) {
|
|
||||||
if (keyCode === "Tab") {
|
|
||||||
this.pushClickEventToGA(
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
]
|
|
||||||
);
|
|
||||||
} else if (keyCode?.includes("Arrow")) {
|
|
||||||
if (window.lastFocusedInputGroup != this.groupName) {
|
|
||||||
this.pushClickEventToGA(
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Radio click
|
|
||||||
window.lastFocusedInputGroup = this.groupName;
|
|
||||||
if (
|
|
||||||
window.firedGaClickEventValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
] !=
|
|
||||||
window.currentlySelectedValues[window.lastFocusedInputGroup]
|
|
||||||
) {
|
|
||||||
this.pushClickEventToGA(
|
|
||||||
window.currentlySelectedValues[
|
|
||||||
window.lastFocusedInputGroup
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isChecked() {
|
isChecked() {
|
||||||
if (this.isMultiSelect && this.modelValue instanceof Array) {
|
if (this.isMultiSelect && this.modelValue instanceof Array) {
|
||||||
return this.modelValue.includes(this.value);
|
return this.modelValue.includes(this.value);
|
||||||
|
} else if (!this.isMultiSelect) {
|
||||||
|
return this.modelValue == this.value;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.modelValue == this.value;
|
|
||||||
},
|
},
|
||||||
inputType() {
|
inputType() {
|
||||||
return this.isMultiSelect ? "checkbox" : "radio";
|
return this.isMultiSelect ? "checkbox" : "radio";
|
||||||
},
|
},
|
||||||
buttonId() {
|
buttonId() {
|
||||||
return `${this.groupName}-${JSON.stringify(this.value)?.replace(
|
return `${this.groupName?.replace(" ", "-")}-${this.value
|
||||||
" ",
|
?.toString()
|
||||||
"-"
|
?.replace(" ", "-")}`;
|
||||||
)}`;
|
},
|
||||||
|
isValueSelectedOnClick() {
|
||||||
|
return this.isMultiSelect || this.selectingInitiatesLoad;
|
||||||
|
},
|
||||||
|
eventTypes() {
|
||||||
|
return {
|
||||||
|
CHANGE: "change",
|
||||||
|
ENTER: "enter",
|
||||||
|
SPACE: "space",
|
||||||
|
CLICK: "click",
|
||||||
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
export const inputButtonProps = {
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [Array, String, Number],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isMultiSelect: Boolean,
|
||||||
|
groupName: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
validationRules: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
valueToLogType: String,
|
||||||
|
isRequired: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
lastValuePushedToGa: [String, Number],
|
||||||
|
setLastValuePushedToGa: Function,
|
||||||
|
selectingInitiatesLoad: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -2,189 +2,171 @@ import { shallowMount } from "@vue/test-utils";
|
||||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
|
||||||
jest.mock("@/store", () => { return {}; }, { virtual: true });
|
jest.mock(
|
||||||
|
"@/store",
|
||||||
|
() => {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
{ virtual: true }
|
||||||
|
);
|
||||||
|
|
||||||
// TODO KO
|
describe("buttonQuestion.vue", () => {
|
||||||
describe.skip("buttonQuestion.vue", () => {
|
|
||||||
it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => {
|
it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(buttonQuestion, {
|
const wrapper = shallowMount(buttonQuestion, {
|
||||||
propsData: {
|
propsData: {
|
||||||
isOverflowScrollable: true,
|
isOverflowScrollable: true,
|
||||||
groupName: "group-name"
|
groupName: "group-name",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
const fieldSet = wrapper.find('fieldset');
|
const fieldSet = wrapper.find("fieldset");
|
||||||
expect(fieldSet.classes()).toContain("overflow-scroll");
|
expect(fieldSet.classes()).toContain("overflow-scroll");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
describe("buttonQuestion.vue", () => {
|
||||||
// it("Fieldset classes should contain row if button type is listCard", () => {
|
it("Fieldset classes should contain row if button type is listCard", () => {
|
||||||
// // Act
|
// Act
|
||||||
// const wrapper = shallowMount(buttonQuestion, {
|
const wrapper = shallowMount(buttonQuestion, {
|
||||||
// propsData: {
|
propsData: {
|
||||||
// buttonType: "listCard",
|
buttonType: "listCard",
|
||||||
// groupName: "group-name"
|
groupName: "group-name",
|
||||||
// }
|
},
|
||||||
// });
|
});
|
||||||
// // Assert
|
// Assert
|
||||||
// const Div = wrapper.find('fieldset div');
|
const Div = wrapper.find("fieldset div");
|
||||||
// expect(Div.classes()).toContain("row");
|
expect(Div.classes()).toContain("row");
|
||||||
// });
|
});
|
||||||
// });
|
});
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
describe("buttonQuestion.vue", () => {
|
||||||
// it("Fieldset classes should contain d-flex if button type is listButtonHorizontal", () => {
|
it("Fieldset classes should contain d-flex if button type is listButtonHorizontal", () => {
|
||||||
// // Act
|
// Act
|
||||||
// const wrapper = shallowMount(buttonQuestion, {
|
const wrapper = shallowMount(buttonQuestion, {
|
||||||
// propsData: {
|
propsData: {
|
||||||
// buttonType: "listButtonHorizontal",
|
buttonType: "listButtonHorizontal",
|
||||||
// groupName: "group-name"
|
groupName: "group-name",
|
||||||
// }
|
},
|
||||||
// });
|
});
|
||||||
// // Assert
|
// Assert
|
||||||
// const Div = wrapper.find('fieldset div');
|
const Div = wrapper.find("fieldset div");
|
||||||
// expect(Div.classes()).toContain("d-flex");
|
expect(Div.classes()).toContain("d-flex");
|
||||||
// });
|
});
|
||||||
// });
|
});
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
describe("buttonQuestion.vue", () => {
|
||||||
// it("Fieldset classes should contain ui-radio if button type is radio", () => {
|
it("Fieldset classes should contain ui-radio if button type is radio", () => {
|
||||||
// // Act
|
// Act
|
||||||
// const wrapper = shallowMount(buttonQuestion, {
|
const wrapper = shallowMount(buttonQuestion, {
|
||||||
// propsData: {
|
propsData: {
|
||||||
// buttonType: "radio",
|
buttonType: "radio",
|
||||||
// groupName: "group-name"
|
groupName: "group-name",
|
||||||
// }
|
},
|
||||||
// });
|
});
|
||||||
// // Assert
|
// Assert
|
||||||
// const Div = wrapper.find('fieldset div');
|
const Div = wrapper.find("fieldset div");
|
||||||
// expect(Div.classes()).toContain("ui-radio");
|
expect(Div.classes()).toContain("ui-radio");
|
||||||
// });
|
});
|
||||||
// });
|
});
|
||||||
|
|
||||||
|
// testing a computed property
|
||||||
|
describe("buttonQuestion.vue", () => {
|
||||||
|
it("getColLength should return '12' if prop isWide is set to true", () => {
|
||||||
|
// Act
|
||||||
|
const localThis = { isWide: true };
|
||||||
|
|
||||||
// // testing a computed property
|
expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("12");
|
||||||
// describe("buttonQuestion.vue", () => {
|
});
|
||||||
// it("getColLength should return '12' if prop isWide is set to true", () => {
|
});
|
||||||
// // Act
|
|
||||||
// const localThis = { isWide: true }
|
|
||||||
|
|
||||||
// expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("12");
|
describe("buttonQuestion.vue", () => {
|
||||||
// });
|
it("getColLength should return '' if prop isWide is set to false", () => {
|
||||||
// });
|
// Act
|
||||||
|
const localThis = {
|
||||||
|
isWide: false,
|
||||||
|
answers: ["a", "b"],
|
||||||
|
groupName: "group-name",
|
||||||
|
};
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("");
|
||||||
// it("getColLength should return '' if prop isWide is set to false", () => {
|
});
|
||||||
// // Act
|
});
|
||||||
// const localThis = {
|
|
||||||
// isWide: false,
|
|
||||||
// answers: ['a', 'b'],
|
|
||||||
// groupName: "group-name"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// expect(buttonQuestion.computed.getColLength.call(localThis)).toBe("");
|
describe("buttonQuestion.vue", () => {
|
||||||
// });
|
it("Should return answer.Text if prop useTextForValue is true", async () => {
|
||||||
// });
|
// Act
|
||||||
|
const localThis = { useTextForValue: true };
|
||||||
|
const answer = { Name: "testName", Text: "testText" };
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
// Assert
|
||||||
// it("Should return answer.Text if prop useTextForValue is true", async () => {
|
expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe(
|
||||||
// // Act
|
"testText"
|
||||||
// const localThis = { useTextForValue: true };
|
);
|
||||||
// const answer = { 'Name': 'testName', 'Text': 'testText' };
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// // Assert
|
describe("buttonQuestion.vue", () => {
|
||||||
// expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe('testText');
|
it("Should return answer.Name if prop useTextForValue is false and there's not buttonLabel and answer.Name exists", async () => {
|
||||||
// });
|
// Act
|
||||||
// });
|
const localThis = { useTextForValue: false };
|
||||||
|
const answer = { Name: "testName", Text: "testText" };
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
// Assert
|
||||||
// it("Should return answer.Name if prop useTextForValue is false and answer.Name exists", async () => {
|
expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe(
|
||||||
// // Act
|
"testName"
|
||||||
// const localThis = { useTextForValue: false };
|
);
|
||||||
// const answer = { 'Name': 'testName', 'Text': 'testText' };
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// // Assert
|
// TODO KO
|
||||||
// expect(buttonQuestion.methods.getValue.call(localThis, answer)).toBe('testName');
|
describe("buttonQuestion.vue", () => {
|
||||||
// });
|
describe.skip("handleAnswerChange", () => {
|
||||||
// });
|
test("is radio => should emit captured value", async () => {
|
||||||
|
// Act
|
||||||
|
const wrapper = shallowMount(
|
||||||
|
buttonQuestion,
|
||||||
|
setupMocks({ propsData: { groupName: "group-name" } })
|
||||||
|
);
|
||||||
|
await wrapper.setProps({
|
||||||
|
answers: ["2022", "2021", "2020"],
|
||||||
|
isMultiSelect: false,
|
||||||
|
modelValue: "",
|
||||||
|
});
|
||||||
|
const val = "2021";
|
||||||
|
wrapper.vm.handleAnswerChange(val);
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
// Assert
|
||||||
// it("Should trigger event modelValue change to new value on when radio button selected", async () => {
|
expect(wrapper.emitted()["update:modelValue"][0]).toEqual(["2021"]);
|
||||||
// // Act
|
});
|
||||||
// const wrapper = shallowMount(buttonQuestion, setupMocks({propsData: {groupName: "group-name"}}));
|
|
||||||
// await wrapper.setProps({
|
|
||||||
// answers: ["2022", "2021", "2020"],
|
|
||||||
// isMultiSelect: false,
|
|
||||||
// modelValue: []
|
|
||||||
// });
|
|
||||||
// const val = { checkValue: true, value: "2021", }
|
|
||||||
// wrapper.vm.handleCheckedChanged(val);
|
|
||||||
// // Assert
|
|
||||||
// expect(wrapper.emitted()["update:modelValue"][0]).toEqual([["2021"]]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
test("is checkbox => should emit captured value", async () => {
|
||||||
// it("Should add values to array on checkbox click", () => {
|
const wrapper = shallowMount(
|
||||||
// // Act
|
buttonQuestion,
|
||||||
// const wrapper = shallowMount(buttonQuestion, setupMocks({
|
setupMocks({ propsData: { groupName: "group-name" } })
|
||||||
// propsData: {
|
);
|
||||||
// modelValue: ["2022", "2021", "2020"],
|
await wrapper.setProps({
|
||||||
// isMultiSelect: true,
|
answers: ["2022", "2021", "2020"],
|
||||||
// groupName: "group-name"
|
isMultiSelect: false,
|
||||||
// }
|
modelValue: "",
|
||||||
// }));
|
});
|
||||||
// const val = { checkValue: true, value: "2019", }
|
const val = ["2022", "2021", , "2019", "2020"];
|
||||||
// wrapper.vm.handleCheckedChanged(val);
|
wrapper.vm.handleAnswerChange(val);
|
||||||
// // Assert
|
|
||||||
// expect(wrapper.emitted()["update:modelValue"][0]).toEqual([["2022", "2021", "2020", "2019"]]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
// Assert
|
||||||
// it("Should add a value to this.selectedValues if prop isMultiSelect is true, checkValue is true and this.selectedValues already exists", () => {
|
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([
|
||||||
// // Act
|
["2022", "2021", , "2019", "2020"],
|
||||||
// const wrapper = shallowMount(buttonQuestion, setupMocks({
|
]);
|
||||||
// propsData: {
|
});
|
||||||
// isMultiSelect: true,
|
});
|
||||||
// modelValue: ['a', 'b'],
|
});
|
||||||
// groupName: "group-name"
|
|
||||||
// }
|
|
||||||
// }));
|
|
||||||
// const val = { checkValue: true, value: "2021", }
|
|
||||||
// wrapper.vm.handleCheckedChanged(val);
|
|
||||||
|
|
||||||
// // Assert
|
|
||||||
// expect(wrapper.vm.selectedValues).toEqual(["a", "b", "2021"]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe("buttonQuestion.vue", () => {
|
|
||||||
// it("Should remove a value to this.selectedValues if prop isMultiSelect is true, checkValue is false and this.selectedValues already exists", () => {
|
|
||||||
// // Act
|
|
||||||
// const wrapper = shallowMount(buttonQuestion, setupMocks({
|
|
||||||
// propsData: {
|
|
||||||
// isMultiSelect: true,
|
|
||||||
// modelValue: ['a', 'b'],
|
|
||||||
// groupName: "group-name"
|
|
||||||
// }
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// const val = { checkValue: false, value: "a", }
|
|
||||||
// wrapper.vm.handleCheckedChanged(val);
|
|
||||||
|
|
||||||
// // Assert
|
|
||||||
// expect(wrapper.vm.selectedValues).toEqual(["b"]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
function setupMocks(mountOptionsMockData = {}) {
|
function setupMocks(mountOptionsMockData = {}) {
|
||||||
const defaultMountOptions = { route: { query: { fmgPage: 'page-name' } } };
|
const defaultMountOptions = { route: { query: { fmgPage: "page-name" } } };
|
||||||
const baseMountOptions = getMountOptions(Object.assign(defaultMountOptions, mountOptionsMockData));
|
const baseMountOptions = getMountOptions(
|
||||||
|
Object.assign(defaultMountOptions, mountOptionsMockData)
|
||||||
|
);
|
||||||
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
|
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
|
||||||
|
|
||||||
return allMountOptions;
|
return allMountOptions;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
<legend
|
<legend
|
||||||
class="sr-only"
|
class="sr-only"
|
||||||
:data-focus-target="formatString(groupName)"
|
:data-focus-target="formatString(groupName)"
|
||||||
|
tabindex="-1"
|
||||||
:id="formatString(groupName)">
|
:id="formatString(groupName)">
|
||||||
{{ questionText }}
|
{{ questionText }}
|
||||||
{{
|
{{
|
||||||
|
|
@ -44,22 +45,21 @@
|
||||||
:groupName="answer.groupName"
|
:groupName="answer.groupName"
|
||||||
:isMultiSelect="isMultiSelect"
|
:isMultiSelect="isMultiSelect"
|
||||||
:value="answer.value"
|
:value="answer.value"
|
||||||
:modelValue="modelValue"
|
|
||||||
:selectingInitiatesLoad="selectingInitiatesLoad"
|
:selectingInitiatesLoad="selectingInitiatesLoad"
|
||||||
:isWide="isWide"
|
:isWide="isWide"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
:textPosition="textPosition"
|
:textPosition="textPosition"
|
||||||
:selectOnKeypress="selectOnKeypress"
|
|
||||||
@blur="handleBlur"
|
|
||||||
@focus="handleFocus"
|
|
||||||
@buttonClicked="handleAnswerChange"
|
|
||||||
:additionalData="additionalData" />
|
:additionalData="additionalData" />
|
||||||
|
:lastValuePushedToGa="lastValuePushedToGa"
|
||||||
|
:setLastValuePushedToGa="setLastValuePushedToGa"
|
||||||
|
v-model="selectedValues"
|
||||||
|
/>
|
||||||
<!-- For nested questions -->
|
<!-- For nested questions -->
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
typeof primaryValue == 'string' &&
|
typeof selectedValues == 'string' &&
|
||||||
primaryValue == answer.value
|
selectedValues == answer.value
|
||||||
">
|
">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -80,9 +80,9 @@
|
||||||
import listButton from "@/ux-components/list-button/list-button";
|
import listButton from "@/ux-components/list-button/list-button";
|
||||||
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
|
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
|
||||||
import listCard from "@/ux-components/list-card/list-card";
|
import listCard from "@/ux-components/list-card/list-card";
|
||||||
import { ErrorMessage } from "vee-validate";
|
|
||||||
import radio from "@/ux-components/radio/radio";
|
import radio from "@/ux-components/radio/radio";
|
||||||
import servicePackageRadio from "@/layouts/quote/service-package-question/service-package-radio/service-package-radio";
|
import servicePackageRadio from "@/layouts/quote/service-package-question/service-package-radio/service-package-radio";
|
||||||
|
import { ErrorMessage } from "vee-validate";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "buttonQuestion",
|
name: "buttonQuestion",
|
||||||
|
|
@ -118,16 +118,11 @@ export default {
|
||||||
suppressError: Boolean,
|
suppressError: Boolean,
|
||||||
useTextForValue: Boolean,
|
useTextForValue: Boolean,
|
||||||
valueToLogType: String,
|
valueToLogType: String,
|
||||||
selectOnKeypress: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
additionalData: null
|
additionalData: null
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
primaryValue: "",
|
lastValuePushedToGa: null,
|
||||||
lastFocusedInputGroup: "",
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -185,7 +180,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
buttonsInfo() {
|
buttonsInfo() {
|
||||||
// TODO KO temporary. It should always just be an array
|
|
||||||
return (Array.isArray(this.answers) ? this.answers : [])?.map(
|
return (Array.isArray(this.answers) ? this.answers : [])?.map(
|
||||||
(answer) => ({
|
(answer) => ({
|
||||||
buttonLabel: answer.buttonLabel ?? answer.Text ?? answer,
|
buttonLabel: answer.buttonLabel ?? answer.Text ?? answer,
|
||||||
|
|
@ -204,6 +198,14 @@ export default {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
selectedValues: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue;
|
||||||
|
},
|
||||||
|
set(selectedAnswers) {
|
||||||
|
this.$emit("update:modelValue", selectedAnswers);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatString(str) {
|
formatString(str) {
|
||||||
|
|
@ -227,21 +229,8 @@ export default {
|
||||||
: this.formatString(answer.toString());
|
: this.formatString(answer.toString());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleAnswerChange(primaryAnswerValue) {
|
setLastValuePushedToGa(lastValuePushedToGa) {
|
||||||
this.primaryValue = primaryAnswerValue;
|
this.lastValuePushedToGa = lastValuePushedToGa;
|
||||||
this.$emit("buttonQuestionChange", primaryAnswerValue);
|
|
||||||
this.$emit("update:modelValue", primaryAnswerValue);
|
|
||||||
},
|
|
||||||
handleBlur() {
|
|
||||||
// this.lastFocusedInputGroup = this.groupName;
|
|
||||||
// window.lastFocusedInputGroup = this.groupName
|
|
||||||
// console.log("blur: ", this.groupName);
|
|
||||||
},
|
|
||||||
handleFocus() {
|
|
||||||
// console.log("focused: ", {
|
|
||||||
// groupName: this.groupName,
|
|
||||||
// lastFocusedInputGroup: this.lastFocusedInputGroup,
|
|
||||||
// });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -1,164 +1,199 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="d-flex justify-content-center">Date Picker</legend>
|
<legend class=" sr-only">Date Picker</legend>
|
||||||
<div class="grid-container">
|
<div class="calendar-grid-container">
|
||||||
|
<div class="month-year body-small d-flex align-items-center ps-3 small">{{currentMonth}} {{currentYear}}</div>
|
||||||
|
<div class="legend caption d-flex align-items-center justify-content-end"><span class="legend-circle me-1"></span> = Available</div>
|
||||||
|
<div class="nav-back ps-3"><button></button></div>
|
||||||
|
<div class="nav-forward pe-3"><button></button></div>
|
||||||
<!-- Do the days of the weeek need to be read? -->
|
<!-- Do the days of the weeek need to be read? -->
|
||||||
<div class="grid-item"><span class="sr-only">Sunday</span>S</div>
|
<div class="grid-item caption"><span class="sr-only">Sunday</span>S</div>
|
||||||
<div class="grid-item"><span class="sr-only">Monday</span>M</div>
|
<div class="grid-item caption"><span class="sr-only">Monday</span>M</div>
|
||||||
<div class="grid-item"><span class="sr-only">Tuesday</span>T</div>
|
<div class="grid-item caption"><span class="sr-only">Tuesday</span>T</div>
|
||||||
<div class="grid-item"><span class="sr-only">Wednesday</span>W</div>
|
<div class="grid-item caption"><span class="sr-only">Wednesday</span>W</div>
|
||||||
<div class="grid-item"><span class="sr-only">Thursday</span>T</div>
|
<div class="grid-item caption"><span class="sr-only">Thursday</span>T</div>
|
||||||
<div class="grid-item"><span class="sr-only">Friday</span>F</div>
|
<div class="grid-item caption"><span class="sr-only">Friday</span>F</div>
|
||||||
<div class="grid-item"><span class="sr-only">Saturday</span>S</div>
|
<div class="grid-item caption"><span class="sr-only">Saturday</span>S</div>
|
||||||
<div class="grid-item radio-wrapper past-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="thirtypast" />
|
<input disabled type="radio" name="day-of-month" id="sep-25" />
|
||||||
<label for="thirtypast"><span>30</span></label>
|
<label class="past-day" for="sep-25"><span>25</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper past-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="thirtyonepast" />
|
<input disabled type="radio" name="day-of-month" id="sep-26" />
|
||||||
<label for="thirtyonepast"><span>31</span></label>
|
<label class="past-day" for="sep-26"><span>26</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day first-of-month">
|
<div class="grid-item radio-wrapper">
|
||||||
<div v-if="isFirstDayOfMonth" class="current-month">OCT</div>
|
<input disabled type="radio" name="day-of-month" id="sep-27" />
|
||||||
<input type="radio" name="day-of-month" id="one" />
|
<label class="past-day" for="sep-27"><span>27</span></label>
|
||||||
<label for="one"><span class="sr-only">{{dayOfWeek}} {{pastMonth}} {{dayOfMonth}}</span><span>1</span></label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="two" />
|
<input disabled type="radio" name="day-of-month" id="sep-28" />
|
||||||
<label for="two"><span>2</span></label>
|
<label class="past-day" for="sep-28"><span>28</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="three" />
|
<input disabled type="radio" name="day-of-month" id="sep-29" />
|
||||||
<label for="three"><span>3</span></label>
|
<label class="past-day" for="sep-29"><span>29</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day" :class="[isCurrentDay ? 'current-day' : '']">
|
<div class="grid-item radio-wrapper">
|
||||||
<div v-if="isCurrentDayDot" class="current-day-dot"></div>
|
<input disabled type="radio" name="day-of-month" id="sep-30" />
|
||||||
<input type="radio" name="day-of-month" id="four" />
|
<label class="past-day" for="sep-30"><span>30</span></label>
|
||||||
<label for="four"><span>4</span></label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<!-- Use this as the base calendar item -->
|
||||||
<input type="radio" name="day-of-month" id="five" />
|
<div class="grid-item radio-wrapper">
|
||||||
<label for="five"><span>5</span></label>
|
<input type="radio" name="day-of-month" id="oct-1" />
|
||||||
|
<label class="highlighted-day selectable-day" :class="[isCurrentDay ? 'current-day' : '']" for="oct-1"><span>1</span>
|
||||||
|
<span class="sr-only">October 1st</span>
|
||||||
|
<div v-if="isFirstDayOfMonth" class="current-month first-day">OCT</div>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<!-- END -->
|
||||||
<input type="radio" name="day-of-month" id="six" />
|
<div class="grid-item radio-wrapper">
|
||||||
<label for="six"><span>6</span></label>
|
<input type="radio" name="day-of-month" id="oct-2" />
|
||||||
|
<label class="selectable-day" for="oct-2"><span>2</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="seven" />
|
<input type="radio" name="day-of-month" id="oct-3" />
|
||||||
<label for="seven"><span>7</span></label>
|
<label class="selectable-day" for="oct-3"><span>3</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="eight" />
|
<input type="radio" name="day-of-month" id="oct-4" />
|
||||||
<label for="eight"><span>8</span></label>
|
<label class="selectable-day" for="oct-4"><span>4</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="nine" />
|
<input type="radio" name="day-of-month" id="oct-5" />
|
||||||
<label for="nine"><span>9</span></label>
|
<label class="selectable-day" for="oct-5"><span>5</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="ten" />
|
<input type="radio" name="day-of-month" id="oct-6" />
|
||||||
<label for="ten"><span>10</span></label>
|
<label class="selectable-day" for="oct-6"><span>6</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="eleven" />
|
<input type="radio" name="day-of-month" id="oct-7" />
|
||||||
<label for="eleven"><span>11</span></label>
|
<label class="selectable-day" for="oct-7"><span>7</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twelve" />
|
<input type="radio" name="day-of-month" id="oct-8" />
|
||||||
<label for="twelve"><span>12</span></label>
|
<label class="selectable-day" for="oct-8"><span>8</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="thirteen" />
|
<input type="radio" name="day-of-month" id="oct-9" />
|
||||||
<label for="thirteen"><span>13</span></label>
|
<label class="selectable-day" for="oct-9"><span>9</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="fourteen" />
|
<input type="radio" name="day-of-month" id="oct-10" />
|
||||||
<label for="fourteen"><span>17</span></label>
|
<label class="selectable-day" for="oct-10"><span>10</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="fifteen" />
|
<input type="radio" name="day-of-month" id="oct-11" />
|
||||||
<label for="fifteen"><span>15</span></label>
|
<label class="selectable-day" for="oct-11"><span>11</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="sixteen" />
|
<input type="radio" name="day-of-month" id="oct-12" />
|
||||||
<label for="sixteen"><span>16</span></label>
|
<label class="selectable-day" for="oct-12"><span>12</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="seventeen" />
|
<input type="radio" name="day-of-month" id="oct-13" />
|
||||||
<label for="seventeen"><span>17</span></label>
|
<label class="selectable-day" for="oct-13"><span>13</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="eighteen" />
|
<input type="radio" name="day-of-month" id="oct-14" />
|
||||||
<label for="eighteen"><span>18</span></label>
|
<label class="selectable-day" for="oct-14"><span>14</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="nineteen" />
|
<input type="radio" name="day-of-month" id="oct-15" />
|
||||||
<label for="nineteen"><span>19</span></label>
|
<label class="selectable-day" for="oct-15"><span>15</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twenty" />
|
<input type="radio" name="day-of-month" id="oct-16" />
|
||||||
<label for="twenty"><span>20</span></label>
|
<label class="selectable-day" for="oct-16"><span>16</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentyone" />
|
<input type="radio" name="day-of-month" id="oct-17" />
|
||||||
<label for="twentyone"><span>21</span></label>
|
<label class="selectable-day" for="oct-17"><span>17</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentytwo" />
|
<input type="radio" name="day-of-month" id="oct-18" />
|
||||||
<label for="twentytwo"><span>22</span></label>
|
<label class="selectable-day" for="oct-18"><span>18</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentythree" />
|
<input type="radio" name="day-of-month" id="oct-19" />
|
||||||
<label for="twentythree"><span>23</span></label>
|
<label class="selectable-day" for="oct-19"><span>19</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentyfour" />
|
<input type="radio" name="day-of-month" id="oct-20" />
|
||||||
<label for="twentyfour"><span>24</span></label>
|
<label class="selectable-day" for="oct-20"><span>20</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentyfive" />
|
<input type="radio" name="day-of-month" id="oct-21" />
|
||||||
<label for="twentyfive"><span>25</span></label>
|
<label class="selectable-day" for="oct-21"><span>21</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentysix" />
|
<input type="radio" name="day-of-month" id="oct-22" />
|
||||||
<label for="twentysix"><span>26</span></label>
|
<label class="selectable-day" for="oct-22"><span>22</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentyseven" />
|
<input type="radio" name="day-of-month" id="oct-23" />
|
||||||
<label for="twentyseven"><span>27</span></label>
|
<label class="selectable-day" for="oct-23"><span>23</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentyeight" />
|
<input type="radio" name="day-of-month" id="oct-24" />
|
||||||
<label for="twentyeight"><span>28</span></label>
|
<label class="selectable-day" for="oct-24"><span>24</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twentynine" />
|
<input type="radio" name="day-of-month" id="oct-25" />
|
||||||
<label for="twentynine"><span>29</span></label>
|
<label class="selectable-day" for="oct-25"><span>25</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="thirty" />
|
<input type="radio" name="day-of-month" id="oct-26" />
|
||||||
<label for="thirty"><span>30</span></label>
|
<label class="selectable-day" for="oct-26"><span>26</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper highlighted-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="thirtyone" />
|
<input type="radio" name="day-of-month" id="oct-27" />
|
||||||
<label for="thirtyone"><span>31</span></label>
|
<label class="selectable-day" for="oct-27"><span>27</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper future-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="onefuture" />
|
<input type="radio" name="day-of-month" id="oct-28" />
|
||||||
<label for="onefuture"><span>1</span></label>
|
<label class="selectable-day" for="oct-28"><span>28</span></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-item radio-wrapper future-day">
|
<div class="grid-item radio-wrapper">
|
||||||
<input type="radio" name="day-of-month" id="twofuture" />
|
<input type="radio" name="day-of-month" id="oct-29" />
|
||||||
<label for="twofuture"><span>2</span></label>
|
<label class="selectable-day" for="oct-29"><span>29</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item radio-wrapper">
|
||||||
|
<input type="radio" name="day-of-month" id="nov-30" />
|
||||||
|
<label class="selectable-day" for="nov-30"><span>30</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item radio-wrapper">
|
||||||
|
<input type="radio" name="day-of-month" id="oct-31" />
|
||||||
|
<label class="selectable-day" for="oct-31"><span>31</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item radio-wrapper">
|
||||||
|
<input type="radio" name="day-of-month" id="nov-1" />
|
||||||
|
<label class="future-day selectable-day" for="nov-1"><span>1</span>
|
||||||
|
<div v-if="isFirstDayOfMonth" class="current-month first-day">OCT</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="grid-item radio-wrapper">
|
||||||
|
<input type="radio" name="day-of-month" id="nov-2" />
|
||||||
|
<label class="future-day selectable-day" for="nov-2"><span>2</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item radio-wrapper">
|
||||||
|
<input type="radio" name="day-of-month" id="nov-3" />
|
||||||
|
<label class="future-day selectable-day" for="nov-3"><span>3</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item radio-wrapper">
|
||||||
|
<input type="radio" name="day-of-month" id="nov-4" />
|
||||||
|
<label class="future-day selectable-day" for="nov-4"><span>4</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="grid-item radio-wrapper">
|
||||||
|
<input type="radio" name="day-of-month" id="nov-5" />
|
||||||
|
<label class="future-day selectable-day" for="nov-5"><span>5</span></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<form class="w-100 d-flex justify-content-center mt-5">
|
|
||||||
<input type="date">
|
|
||||||
</form>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -166,41 +201,94 @@ export default {
|
||||||
name: "datePicker",
|
name: "datePicker",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dayOfWeek: "Tuesday",
|
currentMonth: "October",
|
||||||
dayOfMonth: "1st",
|
currentYear: "2022",
|
||||||
pastMonth: "October",
|
|
||||||
isFirstDayOfMonth: true,
|
isFirstDayOfMonth: true,
|
||||||
isCurrentDay: true,
|
isCurrentDay: true,
|
||||||
isCurrentDayDot: true,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.container {
|
.calendar-grid-container {
|
||||||
//max-width: 341px;
|
|
||||||
label {
|
|
||||||
display: initial; //Override Bootstrap default
|
|
||||||
}
|
|
||||||
#availableDates label:nth-child(14n):after {
|
|
||||||
content: "\a";
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-container {
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-width: 341px;
|
max-width: 414px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: 4px;
|
grid-template-columns: repeat(7, 1fr);
|
||||||
grid-template-columns: auto auto auto auto auto auto auto;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 4px;
|
||||||
|
|
||||||
.grid-item {
|
.grid-item {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 4px;
|
margin: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-year {
|
||||||
|
grid-area: 1 / 1 / 2 / 4;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: .75px;
|
||||||
|
}
|
||||||
|
.legend {
|
||||||
|
grid-area: 1 / 4 / 2 / 6;
|
||||||
|
.legend-circle {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: $blue-100;
|
||||||
|
border: 1px solid $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-forward {
|
||||||
|
grid-area: 1 / 7 / 2 / 8;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
button {
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 7px;
|
||||||
|
height: 12px;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg width='7' height='12' viewBox='0 0 7 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.66831 5.99879C6.66955 6.17554 6.60074 6.34558 6.47695 6.47168L1.15501 11.8017C1.02812 11.9287 0.85603 12 0.676587 12C0.497145 12 0.325053 11.9287 0.198168 11.8017C0.0712831 11.6748 7.268e-09 11.5026 8.07183e-09 11.3231C8.87567e-09 11.1436 0.0712831 10.9714 0.198168 10.8445L5.05126 5.99879L0.198168 1.14736C0.0725521 1.02042 0.00248585 0.848755 0.00338306 0.670131C0.00428028 0.491506 0.0760674 0.320554 0.202952 0.194881C0.329837 0.0692091 0.501426 -0.000888818 0.679971 9.54485e-06C0.858515 0.000906955 1.02939 0.0727263 1.15501 0.199668L6.47312 5.52399C6.59843 5.65017 6.66862 5.82092 6.66831 5.99879Z' fill='%231574A1'/%3E%3C/svg%3E%0A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-back {
|
||||||
|
grid-area: 1 / 6 / 2 / 7;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
button {
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 7px;
|
||||||
|
height: 12px;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg width='7' height='12' viewBox='0 0 7 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.331685 6.00121C0.330445 5.82446 0.399256 5.65442 0.523053 5.52832L5.84499 0.198256C5.97188 0.0713149 6.14397 -8.63821e-08 6.32341 -6.72174e-08C6.50285 -4.80527e-08 6.67495 0.071315 6.80183 0.198256C6.92872 0.325198 7 0.497368 7 0.67689C7 0.856412 6.92872 1.02858 6.80183 1.15552L1.94874 6.00121L6.80183 10.8526C6.92745 10.9796 6.99751 11.1512 6.99662 11.3299C6.99572 11.5085 6.92393 11.6794 6.79705 11.8051C6.67016 11.9308 6.49857 12.0009 6.32003 12C6.14148 11.9991 5.97061 11.9273 5.84499 11.8003L0.526881 6.47601C0.401568 6.34983 0.331375 6.17908 0.331685 6.00121Z' fill='%231574A1'/%3E%3C/svg%3E%0A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-back,
|
||||||
|
.nav-forward {
|
||||||
|
button {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background-color: $blue-100;
|
||||||
|
border: 1px solid $blue;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
&:focus,
|
||||||
|
&:focus-visible {
|
||||||
|
border: 2.5px solid $blue;
|
||||||
|
box-shadow: none;
|
||||||
|
background-color: $blue-100;
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-wrapper {
|
.radio-wrapper {
|
||||||
|
|
@ -208,252 +296,136 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0;
|
outline: none;
|
||||||
width: 46px;
|
|
||||||
height: 46px;
|
|
||||||
|
|
||||||
.current-day-dot {
|
input[type="radio"] {
|
||||||
position: absolute;
|
position: absolute; //override bootstrap
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
}
|
&:focus-visible + label {
|
||||||
|
box-shadow: 0 0 0 2.5px $blue;
|
||||||
&.first-of-month {
|
|
||||||
.current-month {
|
|
||||||
position: absolute;
|
|
||||||
font-size: 9px;
|
|
||||||
top: 4px;
|
|
||||||
color: #1574a1;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&.highlighted-day {
|
&:focus + label,
|
||||||
|
&:checked:focus + label {
|
||||||
input[type="radio"] {
|
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #1574a1;
|
||||||
position: absolute;
|
background-color: $blue;
|
||||||
// opacity: 0;
|
color: $white;
|
||||||
height: 0.1px;
|
&.past-day {
|
||||||
width: 0.1px;
|
box-shadow: none;
|
||||||
|
background-color: transparent;
|
||||||
+ label {
|
color: $gray-500;
|
||||||
position: relative;
|
font-weight: normal;
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 50%;
|
|
||||||
color: #1574a1;
|
|
||||||
|
|
||||||
span {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid #1574a1;
|
|
||||||
background-color: #e4f1f7;
|
|
||||||
color: #1574a1;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
&.current-day {
|
||||||
&:checked {
|
|
||||||
+ label::after {
|
|
||||||
background: #1574a1;
|
|
||||||
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #1574a1;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
+ label span {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
+ label::before {
|
|
||||||
background-color: #1574a1;
|
|
||||||
}
|
|
||||||
+ label span {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.past-day {
|
|
||||||
|
|
||||||
input[type="radio"] {
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
height: 0.1px;
|
|
||||||
width: 0.1px;
|
|
||||||
|
|
||||||
+ label {
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 50%;
|
|
||||||
color: #8E9292;
|
|
||||||
|
|
||||||
span {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
background-color: transparent;
|
|
||||||
color: #1574a1;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:checked {
|
|
||||||
+ label::after {
|
|
||||||
background: #1574a1;
|
|
||||||
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #1574a1;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
+ label span {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
+ label::before {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
+ label span {
|
|
||||||
color: #1574a1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
+ label::before {
|
|
||||||
background-color: #1574a1;
|
|
||||||
}
|
|
||||||
+ label span {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.future-day {
|
|
||||||
|
|
||||||
input[type="radio"] {
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
height: 0.1px;
|
|
||||||
width: 0.1px;
|
|
||||||
|
|
||||||
+ label {
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 50%;
|
|
||||||
color: #4D5151;
|
|
||||||
|
|
||||||
span {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
background-color: transparent;
|
|
||||||
color: #1574a1;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.current-day {
|
|
||||||
|
|
||||||
input[type="radio"] {
|
|
||||||
position: absolute;
|
|
||||||
// opacity: 0;
|
|
||||||
height: 0.1px;
|
|
||||||
width: 0.1px;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: "\A";
|
|
||||||
width:4px;
|
|
||||||
height:4px;
|
|
||||||
border-radius:50%;
|
|
||||||
background: #1574a1;
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
left: -1px;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:checked {
|
|
||||||
+ label::after {
|
|
||||||
background: #1574a1;
|
|
||||||
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #1574a1;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
+ label span {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
&:after {
|
&:after {
|
||||||
background: #fff;
|
background-color: $white;
|
||||||
|
}
|
||||||
|
.first-day {
|
||||||
|
color: $white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:checked + label {
|
||||||
|
color: $white;
|
||||||
|
background: $blue;
|
||||||
|
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $blue;
|
||||||
|
&:after {
|
||||||
|
background-color: $white;
|
||||||
|
}
|
||||||
|
.first-day {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-day {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $gray-600;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
min-width: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&.past-day {
|
||||||
|
color: $gray-500;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selectable-day {
|
||||||
|
color: $blue;
|
||||||
|
background-color: $blue-100;
|
||||||
|
border: 1px solid $blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.current-day {
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
width: .25rem;
|
||||||
|
height: .25rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: $blue;
|
||||||
|
position: absolute;
|
||||||
|
top: 28px;
|
||||||
|
}
|
||||||
|
.first-day {
|
||||||
|
color: $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.future-day {
|
||||||
|
color: $gray-600;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
position: relative;
|
&.small {
|
||||||
top: -.25rem;
|
font-size: .75rem;
|
||||||
|
color: $gray-550;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:checked {
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
box-shadow: 0 0 0 4px transparent;
|
||||||
|
background-color: $blue;
|
||||||
|
color: $white;
|
||||||
|
&:after {
|
||||||
|
background-color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor: pointer;
|
||||||
|
&.current-day {
|
||||||
|
+ .first-day {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.first-day {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ p {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-for="(q, i) in questions" :key="i">
|
<div v-for="(q, i) in questions" :key="i">
|
||||||
<transition appear name="fade" mode="out-in">
|
<transition appear name="fade" mode="out-in">
|
||||||
<!-- <buttonQuestion
|
|
||||||
v-if="q.answerSelected || (q.questionSequence === currentQuestionNum)"
|
|
||||||
class="radioQuestion"
|
|
||||||
:class="(q.questionSequence === currentQuestionNum) && 'current-question'"
|
|
||||||
:questionText="q.questionText"
|
|
||||||
:answers="q.answers"
|
|
||||||
:groupName="`question-${glassIndex}-${q.questionSequence}`"
|
|
||||||
v-model="q.answerSelected"
|
|
||||||
isRequired
|
|
||||||
:validationRules="validationRules"
|
|
||||||
/> -->
|
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
v-if="q.answerSelected || (q.questionSequence === currentQuestionNum)"
|
v-if="q.answerSelected || (q.questionSequence === currentQuestionNum)"
|
||||||
class="radioQuestion"
|
class="radioQuestion"
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ const storeActions = {
|
||||||
LOOKUP_VEHICLE_BY_VIN: "lookupVehicleByVin",
|
LOOKUP_VEHICLE_BY_VIN: "lookupVehicleByVin",
|
||||||
LOOKUP_VIN_BY_PLATE: "lookupVinByPlate",
|
LOOKUP_VIN_BY_PLATE: "lookupVinByPlate",
|
||||||
LOOKUP_VIN_BY_ADDRESS: "lookupVinByAddress",
|
LOOKUP_VIN_BY_ADDRESS: "lookupVinByAddress",
|
||||||
|
|
||||||
GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions",
|
GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions",
|
||||||
GET_PARTS: "getParts",
|
GET_PARTS: "getParts",
|
||||||
GET_CAPABILITY_QUESTIONS: "getCapabilityQuestions",
|
GET_CAPABILITY_QUESTIONS: "getCapabilityQuestions",
|
||||||
GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: "getPartFromCapabilityQuestionAnswer",
|
GET_PART_FROM_CAPABILITY_QUESTION_ANSWER:
|
||||||
|
"getPartFromCapabilityQuestionAnswer",
|
||||||
GET_MOLDING_QUESTIONS: "getMoldingQuestions",
|
GET_MOLDING_QUESTIONS: "getMoldingQuestions",
|
||||||
SAVE_SESSION: "saveSession",
|
SAVE_SESSION: "saveSession",
|
||||||
LOAD_SESSION: "loadSession",
|
LOAD_SESSION: "loadSession",
|
||||||
|
|
@ -46,8 +46,8 @@ const storeActions = {
|
||||||
|
|
||||||
// SAVE COMPONENT STATE
|
// SAVE COMPONENT STATE
|
||||||
SAVE_VEHICLE_YEAR: "saveVehicleYear",
|
SAVE_VEHICLE_YEAR: "saveVehicleYear",
|
||||||
SAVE_VEHICLE_MAKE:"saveVehicleMake",
|
SAVE_VEHICLE_MAKE: "saveVehicleMake",
|
||||||
SAVE_VEHICLE_MODEL:"saveVehicleModel",
|
SAVE_VEHICLE_MODEL: "saveVehicleModel",
|
||||||
SAVE_VEHICLE_STYLE: "saveVehicleStyle",
|
SAVE_VEHICLE_STYLE: "saveVehicleStyle",
|
||||||
SAVE_VEHICLE_DAMAGE: "saveVehicleDamage",
|
SAVE_VEHICLE_DAMAGE: "saveVehicleDamage",
|
||||||
SAVE_VIN_LOOKUP: "saveVinLookup",
|
SAVE_VIN_LOOKUP: "saveVinLookup",
|
||||||
|
|
@ -58,9 +58,10 @@ const storeActions = {
|
||||||
SAVE_REGISTRATION_ADDRESS_LOOKUP: "saveRegistrationAddressLookup",
|
SAVE_REGISTRATION_ADDRESS_LOOKUP: "saveRegistrationAddressLookup",
|
||||||
SAVE_GLASS_PARTS: "saveGlassParts",
|
SAVE_GLASS_PARTS: "saveGlassParts",
|
||||||
SAVE_PART_QUESTION_ANSWERS: "savePartQuestionAnswers",
|
SAVE_PART_QUESTION_ANSWERS: "savePartQuestionAnswers",
|
||||||
RESET_MOLDING_AND_CAPABILITY_QUESTIONS_IF_NEEDED: "resetMoldingAndCapabilityQuestionAnswersIfNeeded",
|
RESET_MOLDING_AND_CAPABILITY_QUESTIONS_IF_NEEDED:
|
||||||
|
"resetMoldingAndCapabilityQuestionAnswersIfNeeded",
|
||||||
SAVE_MOLDING_QUESTION_ANSWERS: "saveMoldingQuestionAnswers",
|
SAVE_MOLDING_QUESTION_ANSWERS: "saveMoldingQuestionAnswers",
|
||||||
SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers"
|
SAVE_CAPABILITY_QUESTION_ANSWERS: "saveCapabilityQuestionAnswers",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { storeActions };
|
export { storeActions };
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
const storeMutations = {
|
const storeMutations = {
|
||||||
|
|
||||||
// VEHICLE MUTATIONS
|
// VEHICLE MUTATIONS
|
||||||
UPDATE_YEAR: "updateYear",
|
UPDATE_YEAR: "updateYear",
|
||||||
UPDATE_MAKE: "updateMake",
|
UPDATE_MAKE: "updateMake",
|
||||||
|
|
@ -22,7 +21,7 @@ const storeMutations = {
|
||||||
UPDATE_GLASS_PARTS: "updateGlassParts",
|
UPDATE_GLASS_PARTS: "updateGlassParts",
|
||||||
UPDATE_OTHER_PARTS: "updateOtherParts",
|
UPDATE_OTHER_PARTS: "updateOtherParts",
|
||||||
|
|
||||||
UPDATE_REGISTRATION_LICENSE_PLATE : "updateRegistrationLicensePlate",
|
UPDATE_REGISTRATION_LICENSE_PLATE: "updateRegistrationLicensePlate",
|
||||||
UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress",
|
UPDATE_REGISTRATION_ADDRESS: "updateRegistrationAddress",
|
||||||
UPDATE_REGISTRATION_CITY: "updateRegistrationCity",
|
UPDATE_REGISTRATION_CITY: "updateRegistrationCity",
|
||||||
UPDATE_REGISTRATION_STATE: "updateRegistrationState",
|
UPDATE_REGISTRATION_STATE: "updateRegistrationState",
|
||||||
|
|
|
||||||
42
src/helpers/button-question-focus-helper.js
Normal file
42
src/helpers/button-question-focus-helper.js
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* Helper for GA click event. When the user mouse clicks on a `base-input-button`, we
|
||||||
|
* push the click event. When the user tabs through a list of radio buttons via a
|
||||||
|
* keyboard, we only want to push the GA click event iff the select was deliberate
|
||||||
|
* (space/enter key) or if there is a selection and the user tabs off of the radio group.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let lastFocusedInputGroupName = "";
|
||||||
|
let onButtonQuestionLostFocusCallback = null;
|
||||||
|
|
||||||
|
// TODO KO add tests
|
||||||
|
const handleAnyComponentFocus = (e) => {
|
||||||
|
const targetType = e.target.type;
|
||||||
|
if (targetType !== "radio" && targetType !== "checkbox") {
|
||||||
|
invokeButtonQuestionLostFocusCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleButtonComponentFocus = (e) => {
|
||||||
|
if (e && lastFocusedInputGroupName !== e.groupName) {
|
||||||
|
invokeButtonQuestionLostFocusCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputComponentBlur = (e) => {
|
||||||
|
if (e) {
|
||||||
|
lastFocusedInputGroupName = e.groupName;
|
||||||
|
onButtonQuestionLostFocusCallback = e.onButtonQuestionLostFocusCallback;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const invokeButtonQuestionLostFocusCallback = () => {
|
||||||
|
if (onButtonQuestionLostFocusCallback) {
|
||||||
|
onButtonQuestionLostFocusCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
handleAnyComponentFocus,
|
||||||
|
handleButtonComponentFocus,
|
||||||
|
handleInputComponentBlur,
|
||||||
|
};
|
||||||
|
|
@ -18,7 +18,6 @@ export async function loadSessionIfPresent() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO KO isOrderDifferent and isOrderSubmitted
|
|
||||||
// Reset state if cookie says to.
|
// Reset state if cookie says to.
|
||||||
if (funnelCookie.ShouldResetState) {
|
if (funnelCookie.ShouldResetState) {
|
||||||
baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,14 @@ describe("addressVehiclesQuestion.vue", () => {
|
||||||
const wrapper = shallowMount(addressVehiclesQuestion, {
|
const wrapper = shallowMount(addressVehiclesQuestion, {
|
||||||
mixins: [mockMixin],
|
mixins: [mockMixin],
|
||||||
propsData: {
|
propsData: {
|
||||||
vehicles: ["1", "2"],
|
vehicles: ["1", "2", "newValue"],
|
||||||
modelValue: ["1", "2"],
|
modelValue: "2",
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const localThis = { $emit: jest.fn() }
|
const localThis = { $emit: jest.fn() }
|
||||||
addressVehiclesQuestion.computed.selectedVehicleVinAsArray.set.call(localThis, ['newValue']);
|
addressVehiclesQuestion.computed.selectedVehicleVin.set.call(localThis, 'newValue');
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(localThis.$emit).toBeCalledWith("update:modelValue", "newValue");
|
expect(localThis.$emit).toBeCalledWith("update:modelValue", "newValue");
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
groupName="ChooseAddressVehicle"
|
groupName="ChooseAddressVehicle"
|
||||||
:questionText="questionText"
|
:questionText="questionText"
|
||||||
:answers="vehicles"
|
:answers="vehicles"
|
||||||
v-model="selectedVehicleVinAsArray"
|
v-model="selectedVehicleVin"
|
||||||
isRequired
|
isRequired
|
||||||
:validation-rules="validationRules"
|
:validation-rules="validationRules"
|
||||||
:valueToLogType="ValueToLogTypes.LAST_5"
|
:valueToLogType="ValueToLogTypes.LAST_5"
|
||||||
|
|
@ -63,18 +63,16 @@ export default {
|
||||||
questionText() {
|
questionText() {
|
||||||
return this.getCmsContent("VehicleConfirmationQuestion", "QuestionText");
|
return this.getCmsContent("VehicleConfirmationQuestion", "QuestionText");
|
||||||
},
|
},
|
||||||
selectedVehicleVinAsArray: {
|
selectedVehicleVin: {
|
||||||
get: function() {
|
get: function() {
|
||||||
const modelValueAsArray = this.modelValue ? [this.modelValue] : [];
|
return this.modelValue;
|
||||||
return modelValueAsArray;
|
|
||||||
},
|
},
|
||||||
set: function(newValue) {
|
set: function(newValue) {
|
||||||
const newValueAsScalar = newValue && newValue.length > 0 ? newValue[newValue.length-1] : null;
|
this.$emit("update:modelValue", newValue);
|
||||||
this.$emit("update:modelValue", newValueAsScalar);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectedVehicle() { // this computed is only needed for the computed differentVehicleAlertBody text above
|
selectedVehicle() { // this computed is only needed for the computed differentVehicleAlertBody text above
|
||||||
return this.vehicles.find( ({ vin }) => vin === this.selectedVehicleVinAsArray[this.selectedVehicleVinAsArray.length-1] );
|
return this.vehicles.find( ({ vin }) => vin === this.selectedVehicleVin[this.selectedVehicleVin.length-1] );
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ export default {
|
||||||
selectedVehicleVin: {
|
selectedVehicleVin: {
|
||||||
handler() {
|
handler() {
|
||||||
// does this vehicle match the previously selected carId?
|
// does this vehicle match the previously selected carId?
|
||||||
this.isCarIdDifferent = this.selectedVehicle.vehicle.carId !== store.getters.vehicle.carId;
|
this.isCarIdDifferent = this.selectedVehicle?.vehicle.carId !== store.getters.vehicle.carId;
|
||||||
if (this.isCarIdDifferent) {
|
if (this.isCarIdDifferent) {
|
||||||
this.$refs.funnelFooter.updateButtonText(`Continue with ${this.selectedVehicle.vehicle.year} ${this.selectedVehicle.vehicle.make} ${this.selectedVehicle.vehicle.model}`);
|
this.$refs.funnelFooter.updateButtonText(`Continue with ${this.selectedVehicle.vehicle.year} ${this.selectedVehicle.vehicle.make} ${this.selectedVehicle.vehicle.model}`);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
:answers="answersToDisplay"
|
:answers="answersToDisplay"
|
||||||
:groupName="groupName"
|
:groupName="groupName"
|
||||||
buttonType="listCard"
|
buttonType="listCard"
|
||||||
v-model="selectedDamageLocations"
|
isRequired
|
||||||
|
v-model="selectedValues"
|
||||||
validationRules="damage-location-required"
|
validationRules="damage-location-required"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -26,12 +27,11 @@ export default ({
|
||||||
name: "damageLocationQuestion",
|
name: "damageLocationQuestion",
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
damageOptions: {},
|
damageOptions: Object,
|
||||||
selectedDamageLocations: this.modelValue
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
modelValue: [Array, String, Number],
|
modelValue: Array,
|
||||||
groupName: String,
|
groupName: String,
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
},
|
},
|
||||||
|
|
@ -47,6 +47,14 @@ export default ({
|
||||||
answersFromCms(){
|
answersFromCms(){
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'Answers');
|
return this.getCmsContent(this.cmsWidgetName, 'Answers');
|
||||||
},
|
},
|
||||||
|
selectedValues: {
|
||||||
|
get: function() {
|
||||||
|
return this.modelValue;
|
||||||
|
},
|
||||||
|
set: function(newValue) {
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
damageOptionsMap(){
|
damageOptionsMap(){
|
||||||
return {
|
return {
|
||||||
Windshield: true,
|
Windshield: true,
|
||||||
|
|
@ -69,11 +77,6 @@ export default ({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
selectedDamageLocations(selectedDamageLocations) {
|
|
||||||
this.$emit("update:modelValue", selectedDamageLocations);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@ describe("replace-options-question.vue", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("replace-options-question.vue", () => {
|
describe("replace-options-question.vue", () => {
|
||||||
// TODO KO
|
test("when updateSelectedValues method is called with a single answerToDisplay it will call to update this.selectedReplaceOptions", async () => {
|
||||||
test.skip("when updateSelectedValues method is called with a single answerToDisplay it will call to update this.selectedValues", async () => {
|
|
||||||
|
|
||||||
//Arrange
|
//Arrange
|
||||||
const { wrapper, cmsContent, replaceOptions
|
const { wrapper, cmsContent, replaceOptions
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
:answers="answersToDisplay"
|
:answers="answersToDisplay"
|
||||||
:groupName="groupName"
|
:groupName="groupName"
|
||||||
buttonType="listCard"
|
buttonType="listCard"
|
||||||
v-model="selectedReplaceOptions"
|
v-model="selectedValues"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
:suppressError="suppressError"
|
:suppressError="suppressError"
|
||||||
:isRequired="isRequired"
|
:isRequired="isRequired"
|
||||||
|
|
@ -20,22 +20,19 @@
|
||||||
<script>
|
<script>
|
||||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
// import buttonQuestionWrapperMixin from "@/mixins/button-question-wrapper-mixin";
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
name: "replaceOptionsQuestion",
|
name: "replaceOptionsQuestion",
|
||||||
// mixins: [buttonQuestionWrapperMixin],
|
data(){
|
||||||
data() {
|
|
||||||
return {
|
return {
|
||||||
replaceOptions: [],
|
replaceOptions: this.isMultiSelect ? [] : "",
|
||||||
selectedReplaceOptions: this.modelValue
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
modelValue: [Array, String, Number],
|
|
||||||
isAvailable: Boolean,
|
isAvailable: Boolean,
|
||||||
filterByVehicleCategory: Boolean,
|
filterByVehicleCategory: Boolean,
|
||||||
groupName: String,
|
groupName: String,
|
||||||
|
modelValue: [Array, String, Number],
|
||||||
isMultiSelect: Boolean,
|
isMultiSelect: Boolean,
|
||||||
validationRules: String,
|
validationRules: String,
|
||||||
suppressError: Boolean,
|
suppressError: Boolean,
|
||||||
|
|
@ -43,15 +40,13 @@ export default ({
|
||||||
isRequired: Boolean,
|
isRequired: Boolean,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initializeComponent(replaceOptions) {
|
initializeComponent(replaceOptions){
|
||||||
this.replaceOptions = replaceOptions;
|
this.replaceOptions = replaceOptions;
|
||||||
},
|
},
|
||||||
updateSelectedValues() {
|
updateSelectedValues() {
|
||||||
// UPDATE SELECTEDVALUES IF ONLY ONE ANSWER
|
// UPDATE SELECTEDVALUES IF ONLY ONE ANSWER
|
||||||
// ex: BackGlass stationary
|
if(Array.isArray(this.answersToDisplay) && this.answersToDisplay.length === 1) {
|
||||||
if (Array.isArray(this.answersToDisplay) && this.answersToDisplay.length === 1) {
|
this.selectedValues = this.isMultiSelect ? [this.answersToDisplay[0].Name] : this.answersToDisplay[0].Name;
|
||||||
const selectedAnswer = this.answersToDisplay[0].Name;
|
|
||||||
this.selectedReplaceOptions = this.isMultiSelect ? [selectedAnswer] : selectedAnswer;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -62,6 +57,14 @@ export default ({
|
||||||
answersFromCms(){
|
answersFromCms(){
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'Answers');
|
return this.getCmsContent(this.cmsWidgetName, 'Answers');
|
||||||
},
|
},
|
||||||
|
selectedValues: {
|
||||||
|
get: function() {
|
||||||
|
return this.modelValue;
|
||||||
|
},
|
||||||
|
set: function(newValue) {
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
answersToDisplay(){
|
answersToDisplay(){
|
||||||
const filteredAnswers = Array.isArray(this.answersFromCms)
|
const filteredAnswers = Array.isArray(this.answersFromCms)
|
||||||
? this.answersFromCms.filter(ans =>
|
? this.answersFromCms.filter(ans =>
|
||||||
|
|
@ -88,11 +91,8 @@ export default ({
|
||||||
},
|
},
|
||||||
shouldDisplayReplaceOptionsQuestion(shouldDisplayReplaceOptionsQuestion) {
|
shouldDisplayReplaceOptionsQuestion(shouldDisplayReplaceOptionsQuestion) {
|
||||||
if (!shouldDisplayReplaceOptionsQuestion) {
|
if (!shouldDisplayReplaceOptionsQuestion) {
|
||||||
this.selectedReplaceOptions = [];
|
this.selectedValues = this.isMultiSelect ? [] : "";
|
||||||
}
|
}
|
||||||
},
|
|
||||||
selectedReplaceOptions(selectedReplaceOptions) {
|
|
||||||
this.$emit("update:modelValue", selectedReplaceOptions);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export default ({
|
||||||
name: "sideDoorOptions",
|
name: "sideDoorOptions",
|
||||||
props: {
|
props: {
|
||||||
groupName: String,
|
groupName: String,
|
||||||
modelValue: Array,
|
modelValue: Object,
|
||||||
selectedDamageLocations: Array,
|
selectedDamageLocations: Array,
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,7 @@ jest.mock("@/store", () => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// TODO KO
|
describe("vehicle-damage.vue", () => {
|
||||||
describe.skip("vehicle-damage.vue", () => {
|
|
||||||
describe("navigation", () => {
|
describe("navigation", () => {
|
||||||
test("BackButtonAction triggers a router.navigateWithoutSaving change", async () => {
|
test("BackButtonAction triggers a router.navigateWithoutSaving change", async () => {
|
||||||
|
|
||||||
|
|
@ -130,20 +129,20 @@ describe.skip("vehicle-damage.vue", () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.vm.selectedDamageLocations = ["Windshield", "SideDoor", "RearWindow"];
|
wrapper.setData({
|
||||||
wrapper.vm.selectedWindshieldOptions = {
|
selectedDamageLocations: ["Windshield", "SideDoor", "RearWindow"],
|
||||||
selectedWindshieldChipCount: null,
|
selectedWindshieldOptions: {
|
||||||
selectedWindshieldReplaceOptions: ["Single"],
|
selectedWindshieldChipCount: null,
|
||||||
selectedWindshieldDamageType: "Replace"
|
selectedWindshieldReplaceOptions: ["Single"],
|
||||||
};
|
selectedWindshieldDamageType: "Replace"
|
||||||
|
},
|
||||||
wrapper.vm.sideDoorOptionsData = {
|
sideDoorOptionsData: {
|
||||||
selectedDoorSides: ["DriverSide", "PassengerSide"],
|
selectedDoorSides: ["DriverSide", "PassengerSide"],
|
||||||
selectedDriverSideReplaceOptions: ["Back"],
|
selectedDriverSideReplaceOptions: ["Back"],
|
||||||
selectedPassengerSideReplaceOptions: ["Quarter"]
|
selectedPassengerSideReplaceOptions: ["Quarter"]
|
||||||
};
|
},
|
||||||
|
selectedRearReplaceOptions: "Stationary",
|
||||||
wrapper.vm.selectedRearReplaceOptions = ["Stationary"];
|
})
|
||||||
|
|
||||||
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" },
|
const expectedGlassToReplace = [{ glassLocation: "Windshield", glassName: "Single" }, { glassLocation: "Driver", glassName: "Back" },
|
||||||
{ glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }];
|
{ glassLocation: "Passenger", glassName: "Quarter" }, { glassLocation: "Rear", glassName: "Stationary" }];
|
||||||
|
|
@ -520,19 +519,19 @@ describe.skip("vehicle-damage.vue", () => {
|
||||||
|
|
||||||
const storeWindshieldOptions = [[1, false, "Windshield", "Single", {
|
const storeWindshieldOptions = [[1, false, "Windshield", "Single", {
|
||||||
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
||||||
selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.SINGLE]
|
selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.SINGLE]
|
||||||
}],
|
}],
|
||||||
[2, false, "Windshield", "Driver", {
|
[2, false, "Windshield", "Driver", {
|
||||||
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
||||||
selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.DRIVER]
|
selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.DRIVER]
|
||||||
}],
|
}],
|
||||||
[3, false, "Windshield", "Passenger", {
|
[3, false, "Windshield", "Passenger", {
|
||||||
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
selectedWindshieldDamageType: damageLocationsSelected.REPLACE,
|
||||||
selectedWindshieldChipCount: [], selectedWindshieldReplaceOptions: [damageLocationsSelected.PASSENGER]
|
selectedWindshieldChipCount: null, selectedWindshieldReplaceOptions: [damageLocationsSelected.PASSENGER]
|
||||||
}],
|
}],
|
||||||
[4, true, "", "", {
|
[4, true, "", "", {
|
||||||
selectedWindshieldDamageType: damageLocationsSelected.REPAIR,
|
selectedWindshieldDamageType: damageLocationsSelected.REPAIR,
|
||||||
selectedWindshieldChipCount: [2], selectedWindshieldReplaceOptions: []
|
selectedWindshieldChipCount: 2, selectedWindshieldReplaceOptions: []
|
||||||
}]
|
}]
|
||||||
];
|
];
|
||||||
test.each(storeWindshieldOptions)("getWindshieldOptionsFromStore test #%s", async (testNum, isRepair, damageLocation, damageName, expectedWindshieldOptions) => {
|
test.each(storeWindshieldOptions)("getWindshieldOptionsFromStore test #%s", async (testNum, isRepair, damageLocation, damageName, expectedWindshieldOptions) => {
|
||||||
|
|
@ -619,8 +618,8 @@ describe.skip("vehicle-damage.vue", () => {
|
||||||
expect(glassSelections).toEqual(expectedGlass);
|
expect(glassSelections).toEqual(expectedGlass);
|
||||||
});
|
});
|
||||||
|
|
||||||
const rearReplaceOptions = [["Rear", "Stationary", [damageLocationsSelected.STATIONARY]],
|
const rearReplaceOptions = [["Rear", "Stationary", damageLocationsSelected.STATIONARY],
|
||||||
["Rear", "Slider", [damageLocationsSelected.SLIDER]]
|
["Rear", "Slider", damageLocationsSelected.SLIDER]
|
||||||
];
|
];
|
||||||
test.each(rearReplaceOptions)("getRearReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => {
|
test.each(rearReplaceOptions)("getRearReplaceOptionsFromStore for %s-%s returns expected %s", async (damageLocation, damageName, expectedGlass) => {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ describe("windshield-chip-count-question.vue", () => {
|
||||||
const { wrapper } = setupMocks({ modelValueProp: 1 });
|
const { wrapper } = setupMocks({ modelValueProp: 1 });
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
await wrapper.setData({ numberOfChips: 2 });
|
wrapper.vm.selectedValue = "2";
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([2]);
|
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([2]);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
:groupName="groupName"
|
:groupName="groupName"
|
||||||
buttonType="listButtonHorizontal"
|
buttonType="listButtonHorizontal"
|
||||||
useTextForValue
|
useTextForValue
|
||||||
v-model="numberOfChips"
|
v-model="selectedValue"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
isRequired
|
isRequired
|
||||||
/>
|
/>
|
||||||
|
|
@ -17,16 +17,9 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||||
// import buttonQuestionWrapperMixin from "@/mixins/button-question-wrapper-mixin";
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
name: "windshieldChipCountQuestion",
|
name: "windshieldOptions",
|
||||||
// mixins: [buttonQuestionWrapperMixin],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
numberOfChips: this.modelValue
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
modelValue: [String, Number],
|
modelValue: [String, Number],
|
||||||
groupName: String,
|
groupName: String,
|
||||||
|
|
@ -41,14 +34,18 @@ export default ({
|
||||||
answersFromCms(){
|
answersFromCms(){
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'Answers');
|
return this.getCmsContent(this.cmsWidgetName, 'Answers');
|
||||||
},
|
},
|
||||||
|
selectedValue: {
|
||||||
|
get: function() {
|
||||||
|
return this.modelValue;
|
||||||
|
},
|
||||||
|
set: function(newValue) {
|
||||||
|
const numberValue = Number(newValue);
|
||||||
|
this.$emit("update:modelValue", numberValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
numberOfChips(numberOfChips) {
|
|
||||||
this.$emit("update:modelValue", numberOfChips);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -15,7 +15,7 @@ describe("windshield-damage-type-question.vue", () => {
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(wrapper.vm.selectedWindshieldDamageType).toEqual("Repair");
|
expect(wrapper.vm.selectedValues).toEqual("Repair");
|
||||||
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ modelValue: "Replace" }]);
|
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{ modelValue: "Replace" }]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<div
|
<div class="windshield-damage-type-question" v-if="isAvailable" aria-live="polite">
|
||||||
class="windshield-damage-type-question"
|
|
||||||
v-if="isAvailable"
|
|
||||||
aria-live="polite">
|
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
:questionText="questionText"
|
:questionText="questionText"
|
||||||
:answers="answersFromCms"
|
:answers="answersFromCms"
|
||||||
:groupName="groupName"
|
:groupName="groupName"
|
||||||
buttonType="listCard"
|
buttonType="listCard"
|
||||||
v-model="selectedWindshieldDamageType"
|
v-model="selectedValues"
|
||||||
:suppressError="suppressError"
|
:suppressError="suppressError"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
isRequired />
|
isRequired
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import buttonQuestion from "@/common-components/button-question/button-question";
|
import buttonQuestion from "@/common-components/button-question/button-question";
|
||||||
// import buttonQuestionWrapperMixin from "@/mixins/button-question-wrapper-mixin";
|
|
||||||
|
|
||||||
export default {
|
export default ({
|
||||||
name: "windshieldDamageTypeQuestion",
|
name: "windshieldDamageTypeQuestion",
|
||||||
// mixins: [buttonQuestionWrapperMixin],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
selectedWindshieldDamageType: this.modelValue,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
modelValue: String,
|
modelValue: String,
|
||||||
groupName: String,
|
groupName: String,
|
||||||
|
|
@ -38,20 +29,23 @@ export default {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
questionText() {
|
questionText(){
|
||||||
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
||||||
},
|
},
|
||||||
answersFromCms() {
|
answersFromCms(){
|
||||||
return this.getCmsContent(this.cmsWidgetName, "Answers");
|
return this.getCmsContent(this.cmsWidgetName, 'Answers');
|
||||||
},
|
},
|
||||||
},
|
selectedValues: {
|
||||||
watch: {
|
get: function() {
|
||||||
selectedWindshieldDamageType(selectedWindshieldDamageType) {
|
return this.modelValue;
|
||||||
this.$emit("update:modelValue", selectedWindshieldDamageType);
|
},
|
||||||
|
set: function(newValue) {
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
},
|
}
|
||||||
};
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -57,8 +57,8 @@ defineRule("windshield-replace-options-required", required(errorMessages.WINSHIE
|
||||||
|
|
||||||
defineRule("check-for-repair-and-replace", (selectedWindshieldDamageType, selectedDamageLocations) => {
|
defineRule("check-for-repair-and-replace", (selectedWindshieldDamageType, selectedDamageLocations) => {
|
||||||
return selectedWindshieldDamageType.toString() != damageLocationsSelected.REPAIR ||
|
return selectedWindshieldDamageType.toString() != damageLocationsSelected.REPAIR ||
|
||||||
!selectedDamageLocations.includes(damageLocationsSelected.WINDSHIELD) ||
|
(!selectedDamageLocations.includes(damageLocationsSelected.WINDSHIELD) && !selectedDamageLocations[0]?.includes(damageLocationsSelected.WINDSHIELD)) ||
|
||||||
selectedDamageLocations.length === 1;
|
(selectedDamageLocations[0].length === 1);
|
||||||
});
|
});
|
||||||
defineRule("repair-only", (value) => {
|
defineRule("repair-only", (value) => {
|
||||||
return value.toString() === damageLocationsSelected.REPAIR;
|
return value.toString() === damageLocationsSelected.REPAIR;
|
||||||
|
|
@ -83,7 +83,7 @@ export default ({
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
modelValue: String,
|
modelValue: Object,
|
||||||
selectedDamageLocations: Array,
|
selectedDamageLocations: Array,
|
||||||
hasRepairReplaceConflict: Boolean,
|
hasRepairReplaceConflict: Boolean,
|
||||||
hasSplitSingleConflict: Boolean,
|
hasSplitSingleConflict: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
class="radioQuestion"
|
class="radioQuestion"
|
||||||
isOverflowScrollable
|
isOverflowScrollable
|
||||||
selectingInitiatesLoad
|
selectingInitiatesLoad
|
||||||
:questionText="questionText"
|
:questionText="questionText"
|
||||||
:answers="makes"
|
:answers="makes"
|
||||||
groupName="ChooseVehicleMake"
|
groupName="ChooseVehicleMake"
|
||||||
textPosition="text-start"
|
textPosition="text-start"
|
||||||
v-model="selectedMake"
|
v-model="selectedValue"
|
||||||
:selectOnKeypress="false"
|
isRequired
|
||||||
isRequired />
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -18,44 +18,44 @@ import buttonQuestion from "@/common-components/button-question/button-question"
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { storeActions } from "@/constants/store-actions.js";
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
// import buttonQuestionWrapperMixin from "../../../mixins/button-question-wrapper-mixin";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "make-question",
|
name: "make-question",
|
||||||
// mixins: [buttonQuestionWrapperMixin],
|
data() {
|
||||||
data() {
|
return {
|
||||||
return {
|
makes: [],
|
||||||
makes: [],
|
};
|
||||||
selectedMake: ""
|
},
|
||||||
};
|
props: {
|
||||||
|
modelValue: String,
|
||||||
|
cmsWidgetName: String,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
questionText(){
|
||||||
|
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
||||||
},
|
},
|
||||||
props: {
|
selectedValue: {
|
||||||
modelValue: String,
|
get: function() {
|
||||||
cmsWidgetName: String,
|
return this.modelValue
|
||||||
|
},
|
||||||
|
set: function(newValue) {
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
buttonQuestion,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadInitialData() {
|
||||||
|
return baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.GET_VEHICLE_MAKES,
|
||||||
|
{ year: store.getters.vehicle.year }
|
||||||
|
);
|
||||||
},
|
},
|
||||||
computed: {
|
initializeComponent(initialData) {
|
||||||
questionText() {
|
this.makes = initialData;
|
||||||
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
buttonQuestion,
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
loadInitialData() {
|
|
||||||
return baseMixin.methods.dispatchStoreAction(
|
|
||||||
storeActions.GET_VEHICLE_MAKES,
|
|
||||||
{ year: store.getters.vehicle.year }
|
|
||||||
);
|
|
||||||
},
|
|
||||||
initializeComponent(initialData) {
|
|
||||||
this.makes = initialData;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
selectedMake(selectedMake) {
|
|
||||||
this.$emit("update:modelValue", selectedMake);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@
|
||||||
:answers="models"
|
:answers="models"
|
||||||
groupName="ChooseVehicleModel"
|
groupName="ChooseVehicleModel"
|
||||||
textPosition="text-start"
|
textPosition="text-start"
|
||||||
v-model="selectedModel"
|
v-model="selectedValue"
|
||||||
:selectOnKeypress="false"
|
|
||||||
isRequired
|
isRequired
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -19,15 +18,12 @@ import buttonQuestion from "@/common-components/button-question/button-question"
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { storeActions } from "@/constants/store-actions.js";
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import buttonQuestionWrapperMixin from "@/mixins/button-question-wrapper-mixin";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "model-question",
|
name: "model-question",
|
||||||
mixins: [buttonQuestionWrapperMixin],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
models: [],
|
models: [],
|
||||||
selectedModel: ""
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -38,6 +34,14 @@ export default {
|
||||||
questionText(){
|
questionText(){
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
||||||
},
|
},
|
||||||
|
selectedValue: {
|
||||||
|
get: function() {
|
||||||
|
return this.modelValue
|
||||||
|
},
|
||||||
|
set: function(newValue) {
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
|
|
@ -53,10 +57,5 @@ export default {
|
||||||
this.models = initialData;
|
this.models = initialData;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
selectedModel(selectedModel) {
|
|
||||||
this.$emit("update:modelValue", selectedModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,7 @@ const featureListData = {
|
||||||
modelValueProp: {}
|
modelValueProp: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO KO
|
describe("glass-part-question.vue", () => {
|
||||||
describe.skip("glass-part-question.vue", () => {
|
|
||||||
|
|
||||||
test("Part data passed in, should map data for ButtonQuestion (radio type)", async () => {
|
test("Part data passed in, should map data for ButtonQuestion (radio type)", async () => {
|
||||||
|
|
||||||
//Arrange
|
//Arrange
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@
|
||||||
altText=""
|
altText=""
|
||||||
isRequired
|
isRequired
|
||||||
:groupName="`${glassLocation}-${glassName}`"
|
:groupName="`${glassLocation}-${glassName}`"
|
||||||
:validationRules="tintValidationRules"
|
:validationRules="tintValidationRules">
|
||||||
>
|
|
||||||
<div class="row my-2" aria-live="polite">
|
<div class="row my-2" aria-live="polite">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
|
|
@ -28,7 +27,7 @@
|
||||||
isRequired
|
isRequired
|
||||||
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
|
:groupName="`${glassLocation}-${glassName}-${selectedTint}`"
|
||||||
:validationRules="partValidationRules"
|
:validationRules="partValidationRules"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</buttonQuestion>
|
</buttonQuestion>
|
||||||
|
|
@ -63,7 +62,10 @@ export default {
|
||||||
glassLocation: String,
|
glassLocation: String,
|
||||||
colorAnswers: Array,
|
colorAnswers: Array,
|
||||||
modelValue: Object,
|
modelValue: Object,
|
||||||
alreadyPopulatedPartsData: Array
|
alreadyPopulatedPartsData: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.LoadPreselectedValues();
|
this.LoadPreselectedValues();
|
||||||
|
|
@ -74,12 +76,18 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
tintValidationRules() {
|
tintValidationRules() {
|
||||||
const validationRuleName = `${this.glassLocation}-${this.glassName}-tint-required`;
|
const validationRuleName = `${this.glassLocation}-${this.glassName}-tint-required`;
|
||||||
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
|
defineRule(
|
||||||
|
validationRuleName,
|
||||||
|
required(errorMessages.OPTION_REQUIRED)
|
||||||
|
);
|
||||||
return validationRuleName;
|
return validationRuleName;
|
||||||
},
|
},
|
||||||
partValidationRules() {
|
partValidationRules() {
|
||||||
const validationRuleName = `${this.glassLocation}-${this.glassName}-part-required`;
|
const validationRuleName = `${this.glassLocation}-${this.glassName}-part-required`;
|
||||||
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
|
defineRule(
|
||||||
|
validationRuleName,
|
||||||
|
required(errorMessages.OPTION_REQUIRED)
|
||||||
|
);
|
||||||
return validationRuleName;
|
return validationRuleName;
|
||||||
},
|
},
|
||||||
colorQuestionText() {
|
colorQuestionText() {
|
||||||
|
|
@ -110,16 +118,29 @@ export default {
|
||||||
return this.modelValue?.partNumber;
|
return this.modelValue?.partNumber;
|
||||||
},
|
},
|
||||||
set(newValue) {
|
set(newValue) {
|
||||||
this.$emit("update:modelValue", this.partsForSelectedTint.filter(part => part.partNumber == newValue)[0]);
|
this.$emit(
|
||||||
|
"update:modelValue",
|
||||||
|
this.partsForSelectedTint.filter(
|
||||||
|
(part) => part.partNumber == newValue
|
||||||
|
)[0]
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
partsForSelectedTint() {
|
partsForSelectedTint() {
|
||||||
const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter(dataForGlassLocationAndName =>
|
const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter(
|
||||||
dataForGlassLocationAndName.glassName == this.glassName &&
|
(dataForGlassLocationAndName) =>
|
||||||
dataForGlassLocationAndName.glassLocation == this.glassLocation);
|
dataForGlassLocationAndName.glassName == this.glassName &&
|
||||||
const matchingGlassParts = matchingGlass?.length == 1 ? matchingGlass[0].parts : [];
|
dataForGlassLocationAndName.glassLocation ==
|
||||||
return matchingGlassParts.filter(part => part.color == this.selectedTint) ?? [];
|
this.glassLocation
|
||||||
|
);
|
||||||
|
const matchingGlassParts =
|
||||||
|
matchingGlass?.length == 1 ? matchingGlass[0].parts : [];
|
||||||
|
return (
|
||||||
|
matchingGlassParts.filter(
|
||||||
|
(part) => part.color == this.selectedTint
|
||||||
|
) ?? []
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Creates a map of the feature list data in the correct Name/Value
|
// Creates a map of the feature list data in the correct Name/Value
|
||||||
|
|
@ -151,7 +172,9 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
PartDataFromApi() {
|
PartDataFromApi() {
|
||||||
return this.$store.getters.pageData(this.$route.query.fmgPage) ?? {};
|
return (
|
||||||
|
this.$store.getters.pageData(this.$route.query.fmgPage) ?? {}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -188,7 +211,8 @@ export default {
|
||||||
// Check if only a single part is present for the tint and set the v-model if it is.
|
// Check if only a single part is present for the tint and set the v-model if it is.
|
||||||
AutoSelectIfSinglePart() {
|
AutoSelectIfSinglePart() {
|
||||||
if (this.partsForSelectedTint?.length == 1) {
|
if (this.partsForSelectedTint?.length == 1) {
|
||||||
this.selectedPartNumber = this.partsForSelectedTint[0].partNumber;
|
this.selectedPartNumber =
|
||||||
|
this.partsForSelectedTint[0].partNumber;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -197,7 +221,7 @@ export default {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.modelValue !== undefined) {
|
if (this.modelValue !== undefined) {
|
||||||
// Populate button-question model-value if parts data already exists in VueX
|
// Populate button-question model-value if parts data already exists in VueX
|
||||||
this.selectedTint = this.alreadyPopulatedPartsData.filter(part => part.partNumber === this.selectedPartNumber)[0]?.color;
|
this.selectedTint = this.modelValue?.color
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -205,8 +229,8 @@ export default {
|
||||||
watch: {
|
watch: {
|
||||||
selectedTint() {
|
selectedTint() {
|
||||||
this.AutoSelectIfSinglePart();
|
this.AutoSelectIfSinglePart();
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ describe("vehicle-parts.vue", () => {
|
||||||
expect(arePagePrerequisitesValid).toBe(true);
|
expect(arePagePrerequisitesValid).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Initial data, should populate this.selectedGlassParts", async () => {
|
test.only("Initial data, should populate this.selectedGlassParts", async () => {
|
||||||
|
|
||||||
//Arrange
|
//Arrange
|
||||||
store.getters.pageData.mockReturnValue(basePartResponse);
|
store.getters.pageData.mockReturnValue(basePartResponse);
|
||||||
|
|
@ -183,7 +183,16 @@ describe("vehicle-parts.vue", () => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
expect(wrapper.vm.selectedGlassParts).toEqual({ "Rear-Stationary": { "Rear": ['DB12209YPYNOEM'] } });
|
expect(wrapper.vm.selectedGlassParts).toEqual({
|
||||||
|
"Rear-Stationary": {
|
||||||
|
partNumber: "DB12209YPYNOEM",
|
||||||
|
description: "heated glass, solar, 1 hole",
|
||||||
|
color: "Gray Tint Privacy",
|
||||||
|
requiresRecalibration: false,
|
||||||
|
requiresCapabilityQuestions: false,
|
||||||
|
childParts: null
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("User had part questions > BackButtonAction triggers a router.navigateWithoutSaving change with correct scenario", async () => {
|
test("User had part questions > BackButtonAction triggers a router.navigateWithoutSaving change with correct scenario", async () => {
|
||||||
|
|
@ -509,6 +518,8 @@ function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {}
|
||||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
||||||
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn();
|
||||||
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
wrapper.vm.$refs.loadingModal.showModal = jest.fn();
|
||||||
|
// wrapper.vm.$refs.onSubmit = jest.fn();
|
||||||
|
// wrapper.vm.$refs.onInvalidSubmit = jest.fn();
|
||||||
|
|
||||||
return { wrapper, apiPromise };
|
return { wrapper, apiPromise };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -204,9 +204,7 @@ export default {
|
||||||
const partNumber = this.alreadyPopulatedPartsData[key].partNumber;
|
const partNumber = this.alreadyPopulatedPartsData[key].partNumber;
|
||||||
g.parts.forEach((p) => {
|
g.parts.forEach((p) => {
|
||||||
if (p.partNumber === partNumber) {
|
if (p.partNumber === partNumber) {
|
||||||
this.selectedGlassParts[g.glassLocation + "-" + g.glassName] = {
|
this.selectedGlassParts[g.glassLocation + "-" + g.glassName] = p;
|
||||||
[g.glassLocation]: [partNumber],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@
|
||||||
:answers="styles"
|
:answers="styles"
|
||||||
groupName="ChooseVehicleStyle"
|
groupName="ChooseVehicleStyle"
|
||||||
textPosition="text-start"
|
textPosition="text-start"
|
||||||
v-model="selectedStyle"
|
v-model="selectedValue"
|
||||||
:selectOnKeypress="false"
|
|
||||||
isRequired
|
isRequired
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -19,24 +18,30 @@ import buttonQuestion from "@/common-components/button-question/button-question"
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { storeActions } from "@/constants/store-actions.js";
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
// import buttonQuestionWrapperMixin from "@/mixins/button-question-wrapper-mixin";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "style-question",
|
name: "style-question",
|
||||||
// mixins: [buttonQuestionWrapperMixin],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
styles: [],
|
styles: [],
|
||||||
selectedStyle: ""
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
modelValue: String,
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
questionText(){
|
questionText(){
|
||||||
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
||||||
},
|
},
|
||||||
|
selectedValue: {
|
||||||
|
get: function() {
|
||||||
|
return this.modelValue
|
||||||
|
},
|
||||||
|
set: function(newValue) {
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
|
|
@ -56,10 +61,5 @@ export default {
|
||||||
this.styles = initialData;
|
this.styles = initialData;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
selectedStyle(selectedStyle) {
|
|
||||||
this.$emit("update:modelValue", selectedStyle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<buttonQuestion
|
||||||
<buttonQuestion
|
class="radioQuestion"
|
||||||
class="radioQuestion"
|
isOverflowScrollable
|
||||||
isOverflowScrollable
|
selectingInitiatesLoad
|
||||||
selectingInitiatesLoad
|
:questionText="questionText"
|
||||||
:questionText="questionText"
|
:answers="years"
|
||||||
:answers="years"
|
groupName="ChooseVehicleYear"
|
||||||
groupName="ChooseVehicleYear"
|
textPosition="text-start"
|
||||||
textPosition="text-start"
|
v-model="selectedValue"
|
||||||
v-model="selectedYear"
|
isRequired
|
||||||
:selectOnKeypress="false"
|
/>
|
||||||
isRequired
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -20,27 +17,32 @@ import buttonQuestion from "@/common-components/button-question/button-question"
|
||||||
// Supporting files
|
// Supporting files
|
||||||
import { storeActions } from "@/constants/store-actions.js";
|
import { storeActions } from "@/constants/store-actions.js";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
// import buttonQuestionWrapperMixin from "@/mixins/button-question-wrapper-mixin";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "year-question",
|
name: "year-question",
|
||||||
// mixins: [buttonQuestionWrapperMixin],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
years: [],
|
years: [],
|
||||||
selectedYear: ""
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
modelValue: String,
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion
|
buttonQuestion,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
questionText() {
|
questionText(){
|
||||||
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
||||||
},
|
},
|
||||||
|
selectedValue: {
|
||||||
|
get: function() {
|
||||||
|
return this.modelValue
|
||||||
|
},
|
||||||
|
set: function(newValue) {
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loadInitialData() {
|
loadInitialData() {
|
||||||
|
|
@ -53,10 +55,5 @@ export default {
|
||||||
this.years = initialData;
|
this.years = initialData;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
selectedYear(selectedYear) {
|
|
||||||
this.$emit("update:modelValue", selectedYear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ export default {
|
||||||
logCustomEvent(category, action, label, value) {
|
logCustomEvent(category, action, label, value) {
|
||||||
const currentPageName = getPageNameByQueryString();
|
const currentPageName = getPageNameByQueryString();
|
||||||
|
|
||||||
console.log("PUSHING: ", label)
|
|
||||||
|
|
||||||
var payload = {
|
var payload = {
|
||||||
userId: getDeviceIdValue(),
|
userId: getDeviceIdValue(),
|
||||||
sessionKey: getSessionKeyValue(),
|
sessionKey: getSessionKeyValue(),
|
||||||
|
|
@ -50,6 +48,7 @@ export default {
|
||||||
pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null) {
|
pushEventToGA(category, action, label, pushToLogApp = false, valueToLogType = null) {
|
||||||
const currentPageName = getPageNameByQueryString();
|
const currentPageName = getPageNameByQueryString();
|
||||||
const labelToLog = getValueToLog(label, valueToLogType);
|
const labelToLog = getValueToLog(label, valueToLogType);
|
||||||
|
|
||||||
const eventToBePushed = {
|
const eventToBePushed = {
|
||||||
'event': GaEvents.GENERIC_EVENT,
|
'event': GaEvents.GENERIC_EVENT,
|
||||||
'category': category,
|
'category': category,
|
||||||
|
|
@ -142,7 +141,7 @@ export default {
|
||||||
|
|
||||||
noSession() {
|
noSession() {
|
||||||
return getSessionKeyValue() === 0 || getSessionIdValue() === '00000000-0000-0000-0000-000000000000';
|
return getSessionKeyValue() === 0 || getSessionIdValue() === '00000000-0000-0000-0000-000000000000';
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
analyticsPageEvents() {
|
analyticsPageEvents() {
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,11 @@ import { vehicleCategories } from "@/constants/vehicle-categories.js";
|
||||||
import { routerParams } from "@/router/router-constants/router-params";
|
import { routerParams } from "@/router/router-constants/router-params";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { dynamicStrings } from "@/constants/dynamic-strings";
|
import { dynamicStrings } from "@/constants/dynamic-strings";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
cmsContentByWidget: {}
|
cmsContentByWidget: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -19,7 +18,9 @@ export default {
|
||||||
this.$root.cmsContentByWidget = cmsContent;
|
this.$root.cmsContentByWidget = cmsContent;
|
||||||
},
|
},
|
||||||
getCmsContent(widgetName, fieldName) {
|
getCmsContent(widgetName, fieldName) {
|
||||||
return this.$root.cmsContentByWidget?.[widgetName]?.[fieldName] ? this.$root.cmsContentByWidget[widgetName][fieldName] : '';
|
return this.$root.cmsContentByWidget?.[widgetName]?.[fieldName]
|
||||||
|
? this.$root.cmsContentByWidget[widgetName][fieldName]
|
||||||
|
: "";
|
||||||
},
|
},
|
||||||
dispatchStoreAction(type, payload, encodePayload = true) {
|
dispatchStoreAction(type, payload, encodePayload = true) {
|
||||||
// Encode the payload if required
|
// Encode the payload if required
|
||||||
|
|
@ -32,7 +33,7 @@ export default {
|
||||||
savePageDataToStore(page, data) {
|
savePageDataToStore(page, data) {
|
||||||
store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: data });
|
store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: data });
|
||||||
},
|
},
|
||||||
onSubmit() { }, // DO NOT REMOVE; needed to prevent default form submit behavior. Cannot use .prevent modifier for vee-validate Form
|
onSubmit() {}, // DO NOT REMOVE; needed to prevent default form submit behavior. Cannot use .prevent modifier for vee-validate Form
|
||||||
onInvalidSubmit({ values, errors, results }) {
|
onInvalidSubmit({ values, errors, results }) {
|
||||||
// identify the first error field and put focus on it
|
// identify the first error field and put focus on it
|
||||||
// get error names array
|
// get error names array
|
||||||
|
|
@ -49,12 +50,15 @@ export default {
|
||||||
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
|
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
|
||||||
},
|
},
|
||||||
async getZipCodeData(zipCode) {
|
async getZipCodeData(zipCode) {
|
||||||
const serviceZipValidationResponse = await this.dispatchStoreAction(storeActions.VALIDATE_ZIP, { zip: zipCode });
|
const serviceZipValidationResponse = await this.dispatchStoreAction(
|
||||||
|
storeActions.VALIDATE_ZIP,
|
||||||
|
{ zip: zipCode }
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isValid: serviceZipValidationResponse.data.isValid,
|
isValid: serviceZipValidationResponse.data.isValid,
|
||||||
isServiceable: serviceZipValidationResponse.data.isServiceable,
|
isServiceable: serviceZipValidationResponse.data.isServiceable,
|
||||||
state: serviceZipValidationResponse.data.state
|
state: serviceZipValidationResponse.data.state,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getEconomyPackagePrice(lineItems) {
|
getEconomyPackagePrice(lineItems) {
|
||||||
|
|
@ -82,13 +86,13 @@ export default {
|
||||||
routerParams() {
|
routerParams() {
|
||||||
return routerParams;
|
return routerParams;
|
||||||
},
|
},
|
||||||
queryStrings(){
|
queryStrings() {
|
||||||
return queryStrings;
|
return queryStrings;
|
||||||
},
|
},
|
||||||
dynamicStrings(){
|
dynamicStrings() {
|
||||||
return dynamicStrings;
|
return dynamicStrings;
|
||||||
},
|
},
|
||||||
cssClassNameForCmsWidget(){
|
cssClassNameForCmsWidget() {
|
||||||
return "widget-name-" + this.cmsWidgetName;
|
return "widget-name-" + this.cmsWidgetName;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { ref, isRef } from "vue";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
modelValue: [Array, String, Number],
|
|
||||||
// modelValueName: {
|
|
||||||
// type: String,
|
|
||||||
// required: true,
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
selectedValue: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.selectedValue = this.modelValue;
|
|
||||||
|
|
||||||
console.log("Created: ", {
|
|
||||||
selectedValue: this.selectedValue,
|
|
||||||
// modelValue: this.modelValue,
|
|
||||||
// modelValueName: this.modelValueName
|
|
||||||
})
|
|
||||||
if (this.modelValueName) {
|
|
||||||
this[this.modelValueName] = this.selectedValue;
|
|
||||||
// this.$on("update:modelValue", (dynamicModelValue) => {
|
|
||||||
// console.log("ON HIT", {
|
|
||||||
// dynamicModelValue: dynamicModelValue
|
|
||||||
// })
|
|
||||||
// this.selectedValue = dynamicModelValue;
|
|
||||||
// this.$emit("update:modelValue", dynamicModelValue)
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,43 +1,36 @@
|
||||||
|
import { inputButtonProps } from "@/common-components/base-input-button/button-functionality-props";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
model: {
|
||||||
|
prop: "modelValue",
|
||||||
|
event: "change",
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
modelValue: [Array, String, Number],
|
...inputButtonProps,
|
||||||
value: [String, Number],
|
|
||||||
isMultiSelect: Boolean,
|
|
||||||
groupName: String,
|
|
||||||
buttonLabel: [Number, String],
|
buttonLabel: [Number, String],
|
||||||
buttonLabelSubCopy: String,
|
buttonLabelSubCopy: String,
|
||||||
buttonImage: String,
|
buttonImage: String,
|
||||||
altText: {
|
altText: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ""
|
default: "",
|
||||||
},
|
},
|
||||||
textPosition: String,
|
textPosition: String,
|
||||||
screenReaderOnlyText: String,
|
screenReaderOnlyText: String,
|
||||||
valueToLogType: String,
|
|
||||||
validationRules: String,
|
|
||||||
isWide: Boolean,
|
isWide: Boolean,
|
||||||
isRequired: Boolean,
|
|
||||||
additionalData: null,
|
additionalData: null,
|
||||||
},
|
},
|
||||||
data() {
|
computed: {
|
||||||
return {
|
selectedValue: {
|
||||||
selectedValue: null,
|
get() {
|
||||||
};
|
return this.modelValue;
|
||||||
},
|
},
|
||||||
mounted() {
|
set(e) {
|
||||||
this.selectedValue = this.modelValue;
|
if (this.preHandleAnswerChange) {
|
||||||
},
|
this.preHandleAnswerChange(e);
|
||||||
methods: {
|
}
|
||||||
handleAnswerChange(e) {
|
|
||||||
if (this.preHandleAnswerChange) {
|
this.$emit("update:modelValue", e);
|
||||||
this.preHandleAnswerChange(e)
|
},
|
||||||
}
|
|
||||||
this.$emit("change", e);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
selectedValue(selectedValue) {
|
|
||||||
this.$emit("update:modelValue", selectedValue);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
81
src/mixins/input-button-wrapper-mixin.spec.js
Normal file
81
src/mixins/input-button-wrapper-mixin.spec.js
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
describe("input-button-wrapper-mixin", () => {
|
||||||
|
describe("mouse clicks", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test.todo("clicking once checks the baseInputButton");
|
||||||
|
|
||||||
|
test.todo("clicking twice unchecks the baseInputButton");
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"is initially checked => checking unchecks the baseInputButton"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo("clicked => correct event and value are emitted");
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test.todo("clicking once selects the baseInputButton");
|
||||||
|
|
||||||
|
test.todo("clicking twice keeps the baseInputButton selected");
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"is initially selected => click keeps the baseInputButton selected"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo("clicked => correct event and value are emitted");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("keyboard navigation and", () => {
|
||||||
|
describe("checkbox", () => {
|
||||||
|
test.todo(
|
||||||
|
"focus on a checkbox => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"blur from a checkbox => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click space on a checkbox => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click space on a checkbox that is already checked => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click enter on a checkbox => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click enter on a checkbox that is already checked => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("radio", () => {
|
||||||
|
test.todo(
|
||||||
|
"focus on a radio button => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"blur from a radio button => inputButtonClicked is not emitted"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click space on a radio button => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click space on a radio button that is already selected => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click enter on a radio button => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
|
||||||
|
test.todo(
|
||||||
|
"focus and click enter on a radio button that is already selected => inputButtonClicked is emitted with correct value"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -136,9 +136,6 @@ export default {
|
||||||
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
|
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
|
||||||
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
|
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
|
||||||
|
|
||||||
console.log({
|
|
||||||
hasGlassLocationWithMultipleParts: hasGlassLocationWithMultipleParts
|
|
||||||
})
|
|
||||||
if (hasPartQuestions && this.currentPageComesBeforePage(currentPage, fmgPageValues.PART_QUESTIONS)) {
|
if (hasPartQuestions && this.currentPageComesBeforePage(currentPage, fmgPageValues.PART_QUESTIONS)) {
|
||||||
self.$router.navigateWithSaving(self.navigationScenarios.HAS_PART_QUESTIONS, self.$route, {}, {}, { partsOrQuestions: partsOrQuestions });
|
self.$router.navigateWithSaving(self.navigationScenarios.HAS_PART_QUESTIONS, self.$route, {}, {}, { partsOrQuestions: partsOrQuestions });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,8 +239,6 @@ function navigateToUrl(url, optionalQuery = {}) {
|
||||||
externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
|
externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
|
||||||
}
|
}
|
||||||
|
|
||||||
externalUrl.searchParams.append("experiments", "ConceptFunnel=ConceptFunnel_V1=ConceptFunnel_TEST=true");
|
|
||||||
|
|
||||||
window.location.assign(externalUrl);
|
window.location.assign(externalUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { createStore } from "vuex";
|
import { createStore, Store } from "vuex";
|
||||||
import { endpoints } from "@/constants/endpoints.js";
|
import { endpoints } from "@/constants/endpoints.js";
|
||||||
import { storeMutations } from "@/constants/store-mutations";
|
import { storeMutations } from "@/constants/store-mutations";
|
||||||
import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper";
|
import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper";
|
||||||
|
|
@ -53,19 +53,19 @@ const getDefaultState = () => {
|
||||||
capabilityQuestionAnswers: null,
|
capabilityQuestionAnswers: null,
|
||||||
},
|
},
|
||||||
lineItems: {
|
lineItems: {
|
||||||
glassParts: null
|
glassParts: null,
|
||||||
},
|
},
|
||||||
payment: {
|
payment: {
|
||||||
isInsurance: null,
|
isInsurance: null,
|
||||||
insuranceCoverage: {
|
insuranceCoverage: {
|
||||||
isVerified: null
|
isVerified: null,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
referralNumber: null,
|
referralNumber: null,
|
||||||
referralDate: null,
|
referralDate: null,
|
||||||
referralCorrelationId: null,
|
referralCorrelationId: null,
|
||||||
accountNumber: 0,
|
accountNumber: 0,
|
||||||
eon: null
|
eon: null,
|
||||||
},
|
},
|
||||||
applicationUser: {
|
applicationUser: {
|
||||||
eventBus: [],
|
eventBus: [],
|
||||||
|
|
@ -76,9 +76,15 @@ const getDefaultState = () => {
|
||||||
crmCustomerId: null,
|
crmCustomerId: null,
|
||||||
lastPageVisited: null,
|
lastPageVisited: null,
|
||||||
experiments: [],
|
experiments: [],
|
||||||
triggeredSiteEntry: false
|
triggeredSiteEntry: false,
|
||||||
},
|
},
|
||||||
}
|
// gaClickInformation: {
|
||||||
|
// currentlySelectedValues: {},
|
||||||
|
// firedGaClickEventValues: {},
|
||||||
|
// lastFocusedInputGroup: "",
|
||||||
|
// wasLastFocusedInputMultiselect: undefined,
|
||||||
|
// },
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const state = getDefaultState();
|
export const state = getDefaultState();
|
||||||
|
|
@ -195,7 +201,6 @@ export const mutations = {
|
||||||
state.order.customer.emailAddress = customerEmailAddress;
|
state.order.customer.emailAddress = customerEmailAddress;
|
||||||
},
|
},
|
||||||
updateVehicle(state, vehicleInfo) {
|
updateVehicle(state, vehicleInfo) {
|
||||||
|
|
||||||
state.order.vehicle.year = vehicleInfo.year;
|
state.order.vehicle.year = vehicleInfo.year;
|
||||||
state.order.vehicle.make = vehicleInfo.make;
|
state.order.vehicle.make = vehicleInfo.make;
|
||||||
state.order.vehicle.model = vehicleInfo.model;
|
state.order.vehicle.model = vehicleInfo.model;
|
||||||
|
|
@ -209,7 +214,8 @@ export const mutations = {
|
||||||
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
|
state.order.vehicle.imageColor = vehicleInfo.imageVifColor;
|
||||||
},
|
},
|
||||||
updateRegistration(state, registrationInfo) {
|
updateRegistration(state, registrationInfo) {
|
||||||
state.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate;
|
state.order.vehicle.registration.licensePlate =
|
||||||
|
registrationInfo?.licensePlate;
|
||||||
state.order.vehicle.registration.address = registrationInfo?.address;
|
state.order.vehicle.registration.address = registrationInfo?.address;
|
||||||
state.order.vehicle.registration.city = registrationInfo?.city;
|
state.order.vehicle.registration.city = registrationInfo?.city;
|
||||||
state.order.vehicle.registration.state = registrationInfo?.state;
|
state.order.vehicle.registration.state = registrationInfo?.state;
|
||||||
|
|
@ -235,7 +241,7 @@ export const mutations = {
|
||||||
state.applicationUser.crmCustomerId = crmCustomerId;
|
state.applicationUser.crmCustomerId = crmCustomerId;
|
||||||
},
|
},
|
||||||
updateLastPageVisited(state, lastPageVisited) {
|
updateLastPageVisited(state, lastPageVisited) {
|
||||||
state.applicationUser.lastPageVisited = lastPageVisited
|
state.applicationUser.lastPageVisited = lastPageVisited;
|
||||||
},
|
},
|
||||||
// EVENT BUS MUTATIONS
|
// EVENT BUS MUTATIONS
|
||||||
addEventToBus(state, event) {
|
addEventToBus(state, event) {
|
||||||
|
|
@ -244,8 +250,7 @@ export const mutations = {
|
||||||
removeEventFromBus(state, eventData) {
|
removeEventFromBus(state, eventData) {
|
||||||
const matchedEvent = state.applicationUser.eventBus.find(
|
const matchedEvent = state.applicationUser.eventBus.find(
|
||||||
({ category, subCategory }) =>
|
({ category, subCategory }) =>
|
||||||
category === eventData.category &&
|
category === eventData.category && subCategory === eventData.subCategory
|
||||||
subCategory === eventData.subCategory
|
|
||||||
);
|
);
|
||||||
const itemIndex = state.applicationUser.eventBus.indexOf(matchedEvent);
|
const itemIndex = state.applicationUser.eventBus.indexOf(matchedEvent);
|
||||||
|
|
||||||
|
|
@ -331,7 +336,7 @@ export const mutations = {
|
||||||
state: orderInformation.vehicle.registration.state,
|
state: orderInformation.vehicle.registration.state,
|
||||||
zipCode: orderInformation.vehicle.registration.zipCode,
|
zipCode: orderInformation.vehicle.registration.zipCode,
|
||||||
licensePlate: orderInformation.vehicle.registration.licensePlateNumber,
|
licensePlate: orderInformation.vehicle.registration.licensePlateNumber,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
state.order.damage.glassToReplace = orderInformation.damage.glassToReplace;
|
state.order.damage.glassToReplace = orderInformation.damage.glassToReplace;
|
||||||
|
|
@ -340,13 +345,18 @@ export const mutations = {
|
||||||
|
|
||||||
state.order.lineItems.glassParts = orderInformation.parts;
|
state.order.lineItems.glassParts = orderInformation.parts;
|
||||||
state.order.accountNumber = orderInformation.accountNumber;
|
state.order.accountNumber = orderInformation.accountNumber;
|
||||||
state.order.serviceLocation.address = orderInformation.serviceLocation.streetAddress,
|
(state.order.serviceLocation.address =
|
||||||
state.order.serviceLocation.city = orderInformation.serviceLocation.city,
|
orderInformation.serviceLocation.streetAddress),
|
||||||
state.order.serviceLocation.state = orderInformation.serviceLocation.state,
|
(state.order.serviceLocation.city =
|
||||||
state.order.serviceLocation.zipCode = orderInformation.serviceLocation.zipCode;
|
orderInformation.serviceLocation.city),
|
||||||
|
(state.order.serviceLocation.state =
|
||||||
|
orderInformation.serviceLocation.state),
|
||||||
|
(state.order.serviceLocation.zipCode =
|
||||||
|
orderInformation.serviceLocation.zipCode);
|
||||||
|
|
||||||
state.order.payment.isInsurance = orderInformation.IsInsuranceOrder;
|
state.order.payment.isInsurance = orderInformation.IsInsuranceOrder;
|
||||||
state.order.payment.insuranceCoverage.isVerified = orderInformation?.insuranceInfo.coverageVerified;
|
state.order.payment.insuranceCoverage.isVerified =
|
||||||
|
orderInformation?.insuranceInfo.coverageVerified;
|
||||||
|
|
||||||
state.order.customer.emailAddress = orderInformation.customer.emailAddress;
|
state.order.customer.emailAddress = orderInformation.customer.emailAddress;
|
||||||
state.applicationUser.experiments = orderInformation.experiments;
|
state.applicationUser.experiments = orderInformation.experiments;
|
||||||
|
|
@ -356,8 +366,23 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
updateTriggeredSiteEntry(state, wasSiteEntryTriggered) {
|
updateTriggeredSiteEntry(state, wasSiteEntryTriggered) {
|
||||||
state.applicationUser.triggeredSiteEntry = wasSiteEntryTriggered;
|
state.applicationUser.triggeredSiteEntry = wasSiteEntryTriggered;
|
||||||
}
|
},
|
||||||
}
|
// START GA click event mutations
|
||||||
|
// updateCurrentlySelectedValues(state, groupName, value) {
|
||||||
|
// state.gaClickInformation.currentlySelectedValues[groupName] = value;
|
||||||
|
// },
|
||||||
|
// updateFiredGaClickEventValues(state, groupName, value) {
|
||||||
|
// state.gaClickInformation.firedGaClickEventValues[groupName] = value;
|
||||||
|
// },
|
||||||
|
// updateLastFocusedInputGroup(state, groupName) {
|
||||||
|
// state.gaClickInformation.lastFocusedInputGroup = groupName;
|
||||||
|
// },
|
||||||
|
// updateWasLastFocusedInputMultiselect(state, wasLastFocusedInputMultiselect) {
|
||||||
|
// state.gaClickInformation.wasLastFocusedInputMultiselect =
|
||||||
|
// wasLastFocusedInputMultiselect;
|
||||||
|
// },
|
||||||
|
// END GA click event mutations
|
||||||
|
};
|
||||||
|
|
||||||
// Export Getters
|
// Export Getters
|
||||||
export const getters = {
|
export const getters = {
|
||||||
|
|
@ -377,7 +402,9 @@ export const getters = {
|
||||||
return !!nonWindshieldItems.length;
|
return !!nonWindshieldItems.length;
|
||||||
},
|
},
|
||||||
lineItems: (state) => state.order.lineItems,
|
lineItems: (state) => state.order.lineItems,
|
||||||
pageData: (state) => (page) => { return state.applicationUser.pageData[page]; },
|
pageData: (state) => (page) => {
|
||||||
|
return state.applicationUser.pageData[page];
|
||||||
|
},
|
||||||
applicationUser: (state) => state.applicationUser,
|
applicationUser: (state) => state.applicationUser,
|
||||||
order: (state) => state.order,
|
order: (state) => state.order,
|
||||||
payment: (state) => state.order.payment,
|
payment: (state) => state.order.payment,
|
||||||
|
|
@ -394,7 +421,8 @@ export const getters = {
|
||||||
funnelServiceState: state.order.serviceLocation.state,
|
funnelServiceState: state.order.serviceLocation.state,
|
||||||
funnelServiceZipCode: state.order.serviceLocation.zipCode,
|
funnelServiceZipCode: state.order.serviceLocation.zipCode,
|
||||||
funnelParentAccountNumber: state.order.accountNumber,
|
funnelParentAccountNumber: state.order.accountNumber,
|
||||||
funnelIsCoverageVerified: state.order.payment.insuranceCoverage.isVerified,
|
funnelIsCoverageVerified:
|
||||||
|
state.order.payment.insuranceCoverage.isVerified,
|
||||||
funnelHasRecalibrationPart: getHasRecalibrationPart(state),
|
funnelHasRecalibrationPart: getHasRecalibrationPart(state),
|
||||||
funnelSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1,
|
funnelSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1,
|
||||||
funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.WINDSHIELD),
|
funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, "glassLocation").includes(damageLocationsSelected.WINDSHIELD),
|
||||||
|
|
@ -407,8 +435,12 @@ export const getters = {
|
||||||
funnelOrderPartTypes: [...getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType"), ...getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.otherParts, "recalibrationType")],
|
funnelOrderPartTypes: [...getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, "recalibrationType"), ...getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.otherParts, "recalibrationType")],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
experimentSettings: (state) => state.applicationUser.experiments.map(x => x.settings).reduce((r, c) => Object.assign(r, c), {}) ?? {}
|
experimentSettings: (state) =>
|
||||||
}
|
state.applicationUser.experiments
|
||||||
|
.map((x) => x.settings)
|
||||||
|
.reduce((r, c) => Object.assign(r, c), {}) ?? {},
|
||||||
|
// gaClickInformation: (state) => state.gaClickInformation,
|
||||||
|
};
|
||||||
|
|
||||||
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
||||||
return (array ?? []).map(x => x[propertyName]).filter(x => x);
|
return (array ?? []).map(x => x[propertyName]).filter(x => x);
|
||||||
|
|
@ -416,7 +448,6 @@ function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
|
||||||
|
|
||||||
// Export Actions
|
// Export Actions
|
||||||
export const actions = {
|
export const actions = {
|
||||||
|
|
||||||
// Vehicle API Actions
|
// Vehicle API Actions
|
||||||
getVehicleYears(context) {
|
getVehicleYears(context) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
|
|
@ -447,11 +478,14 @@ export const actions = {
|
||||||
endpoint: endpoints.LookupVinByPlate.url,
|
endpoint: endpoints.LookupVinByPlate.url,
|
||||||
payload: {
|
payload: {
|
||||||
licensePlate: licensePlate,
|
licensePlate: licensePlate,
|
||||||
licenseState: licenseState
|
licenseState: licenseState,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
lookupVinByAddress(context, { licenseLastName, licenseStreetAddress, licenseZip, licenseState }) {
|
lookupVinByAddress(
|
||||||
|
context,
|
||||||
|
{ licenseLastName, licenseStreetAddress, licenseZip, licenseState }
|
||||||
|
) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LookupVinByAddress.method,
|
method: endpoints.LookupVinByAddress.method,
|
||||||
endpoint: endpoints.LookupVinByAddress.url,
|
endpoint: endpoints.LookupVinByAddress.url,
|
||||||
|
|
@ -459,7 +493,7 @@ export const actions = {
|
||||||
licenseLastName: licenseLastName,
|
licenseLastName: licenseLastName,
|
||||||
licenseStreetAddress: licenseStreetAddress,
|
licenseStreetAddress: licenseStreetAddress,
|
||||||
licenseZip: licenseZip,
|
licenseZip: licenseZip,
|
||||||
licenseState: licenseState
|
licenseState: licenseState,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -493,10 +527,22 @@ export const actions = {
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
context.commit(storeMutations.UPDATE_CAR_ID, response.data.carId);
|
context.commit(storeMutations.UPDATE_CAR_ID, response.data.carId);
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, response.data.category);
|
context.commit(
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, response.data.imageUrl);
|
storeMutations.UPDATE_VEHICLE_CATEGORY,
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, response.data.imageVifNumber);
|
response.data.category
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, response.data.imageVifColor);
|
);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_VEHICLE_IMAGE_URL,
|
||||||
|
response.data.imageUrl
|
||||||
|
);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER,
|
||||||
|
response.data.imageVifNumber
|
||||||
|
);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_VEHICLE_IMAGE_COLOR,
|
||||||
|
response.data.imageVifColor
|
||||||
|
);
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -510,8 +556,8 @@ export const actions = {
|
||||||
validateZip(context, { zip }) {
|
validateZip(context, { zip }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
methods: endpoints.ValidateZip.method,
|
methods: endpoints.ValidateZip.method,
|
||||||
endpoint: `${endpoints.ValidateZip.url}/${zip}`
|
endpoint: `${endpoints.ValidateZip.url}/${zip}`,
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Dependency Actions
|
// Dependency Actions
|
||||||
|
|
@ -526,7 +572,7 @@ export const actions = {
|
||||||
},
|
},
|
||||||
resetRegistrationAndDependencies(context) {
|
resetRegistrationAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
||||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE)
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
},
|
},
|
||||||
resetPartsAndDependencies(context) {
|
resetPartsAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
|
|
@ -582,8 +628,8 @@ export const actions = {
|
||||||
assignmentId: experiment.assignmentId,
|
assignmentId: experiment.assignmentId,
|
||||||
sessionKey: sessionKey,
|
sessionKey: sessionKey,
|
||||||
pageName: pageName,
|
pageName: pageName,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -591,13 +637,28 @@ export const actions = {
|
||||||
updateStoreWithSaveSessionResponse(context, { referralNumber, referralDate, referralCorrelationId, eon, accountNumber, savedSessionId, crmCustomerId }) {
|
updateStoreWithSaveSessionResponse(context, { referralNumber, referralDate, referralCorrelationId, eon, accountNumber, savedSessionId, crmCustomerId }) {
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
|
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
|
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, referralCorrelationId);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_REFERRAL_CORRELATION_ID,
|
||||||
|
referralCorrelationId
|
||||||
|
);
|
||||||
context.commit(storeMutations.UPDATE_EON, eon);
|
context.commit(storeMutations.UPDATE_EON, eon);
|
||||||
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, accountNumber);
|
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, accountNumber);
|
||||||
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
||||||
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
||||||
},
|
},
|
||||||
logPageView(context, { userId, sessionKey, pageName, sessionId, action, event, shouldUseSessionId, experimentsForUser }) {
|
logPageView(
|
||||||
|
context,
|
||||||
|
{
|
||||||
|
userId,
|
||||||
|
sessionKey,
|
||||||
|
pageName,
|
||||||
|
sessionId,
|
||||||
|
action,
|
||||||
|
event,
|
||||||
|
shouldUseSessionId,
|
||||||
|
experimentsForUser,
|
||||||
|
}
|
||||||
|
) {
|
||||||
var payload = {
|
var payload = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
sessionKey: sessionKey,
|
sessionKey: sessionKey,
|
||||||
|
|
@ -607,17 +668,31 @@ export const actions = {
|
||||||
action: action,
|
action: action,
|
||||||
event: event,
|
event: event,
|
||||||
shouldUseSessionId: shouldUseSessionId,
|
shouldUseSessionId: shouldUseSessionId,
|
||||||
experimentsForUser: experimentsForUser
|
experimentsForUser: experimentsForUser,
|
||||||
};
|
};
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LogPageView.method,
|
method: endpoints.LogPageView.method,
|
||||||
endpoint: endpoints.LogPageView.url,
|
endpoint: endpoints.LogPageView.url,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
logApiCall: false
|
logApiCall: false,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
logCustomEvent(context, { userId, sessionKey, pageName, sessionId, category, action, label, value, shouldUseSessionId, experimentsForUser }) {
|
logCustomEvent(
|
||||||
|
context,
|
||||||
|
{
|
||||||
|
userId,
|
||||||
|
sessionKey,
|
||||||
|
pageName,
|
||||||
|
sessionId,
|
||||||
|
category,
|
||||||
|
action,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
shouldUseSessionId,
|
||||||
|
experimentsForUser,
|
||||||
|
}
|
||||||
|
) {
|
||||||
var payload = {
|
var payload = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
sessionKey: sessionKey,
|
sessionKey: sessionKey,
|
||||||
|
|
@ -629,14 +704,14 @@ export const actions = {
|
||||||
label: label,
|
label: label,
|
||||||
value: value,
|
value: value,
|
||||||
shouldUseSessionId: shouldUseSessionId,
|
shouldUseSessionId: shouldUseSessionId,
|
||||||
experimentsForUser: experimentsForUser
|
experimentsForUser: experimentsForUser,
|
||||||
};
|
};
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LogCustomEvent.method,
|
method: endpoints.LogCustomEvent.method,
|
||||||
endpoint: endpoints.LogCustomEvent.url,
|
endpoint: endpoints.LogCustomEvent.url,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
logApiCall: false
|
logApiCall: false,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
initializeSession(context, { userId, sessionId, userAgent, referrer }) {
|
initializeSession(context, { userId, sessionId, userAgent, referrer }) {
|
||||||
|
|
@ -648,22 +723,28 @@ export const actions = {
|
||||||
userAgent: userAgent,
|
userAgent: userAgent,
|
||||||
operatorId: "WEB",
|
operatorId: "WEB",
|
||||||
userName: "SafeliteConceptFunnel",
|
userName: "SafeliteConceptFunnel",
|
||||||
referrer: referrer
|
referrer: referrer,
|
||||||
};
|
};
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.InitializeSession.method,
|
method: endpoints.InitializeSession.method,
|
||||||
endpoint: endpoints.InitializeSession.url,
|
endpoint: endpoints.InitializeSession.url,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
logApiCall: false
|
logApiCall: false,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Misc Actions
|
// Misc Actions
|
||||||
setReferralInformation(context, { referralNumber, referralDate, referralCorrelationId, eon }) {
|
setReferralInformation(
|
||||||
|
context,
|
||||||
|
{ referralNumber, referralDate, referralCorrelationId, eon }
|
||||||
|
) {
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
|
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
|
context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
|
||||||
context.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, referralCorrelationId);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_REFERRAL_CORRELATION_ID,
|
||||||
|
referralCorrelationId
|
||||||
|
);
|
||||||
context.commit(storeMutations.UPDATE_EON, eon);
|
context.commit(storeMutations.UPDATE_EON, eon);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -671,11 +752,14 @@ export const actions = {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetExperimentsByUser.method,
|
method: endpoints.GetExperimentsByUser.method,
|
||||||
endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`,
|
endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`,
|
||||||
payload: {}
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async runExperimentsForTrigger(context, { userId, triggerEvent, triggerValue }) {
|
async runExperimentsForTrigger(
|
||||||
|
context,
|
||||||
|
{ userId, triggerEvent, triggerValue }
|
||||||
|
) {
|
||||||
if (triggerEvent == experimentTriggers.SITE_ENTRY) {
|
if (triggerEvent == experimentTriggers.SITE_ENTRY) {
|
||||||
context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true);
|
context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true);
|
||||||
}
|
}
|
||||||
|
|
@ -685,7 +769,7 @@ export const actions = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
triggerEvent: triggerEvent,
|
triggerEvent: triggerEvent,
|
||||||
triggerValue: triggerValue,
|
triggerValue: triggerValue,
|
||||||
experimentOrder: context.getters.experimentOrder
|
experimentOrder: context.getters.experimentOrder,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await globalMethods.callHttpClient({
|
const response = await globalMethods.callHttpClient({
|
||||||
|
|
@ -694,7 +778,10 @@ export const actions = {
|
||||||
payload: payload,
|
payload: payload,
|
||||||
});
|
});
|
||||||
|
|
||||||
context.commit(storeMutations.UPDATE_EXPERIMENTS, response.data.experiments);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_EXPERIMENTS,
|
||||||
|
response.data.experiments
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
getEvoxImage(context, { relativeUrl }) {
|
getEvoxImage(context, { relativeUrl }) {
|
||||||
|
|
@ -723,7 +810,7 @@ export const actions = {
|
||||||
carId: carId,
|
carId: carId,
|
||||||
glass: glassArray ?? [],
|
glass: glassArray ?? [],
|
||||||
zip: zipCode,
|
zip: zipCode,
|
||||||
vin: vin
|
vin: vin,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -748,7 +835,7 @@ export const actions = {
|
||||||
glass: glassArray,
|
glass: glassArray,
|
||||||
answerResults: resultsArray,
|
answerResults: resultsArray,
|
||||||
zip: zipCode,
|
zip: zipCode,
|
||||||
vin: vin
|
vin: vin,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -757,24 +844,31 @@ export const actions = {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetCapabilityQuestions.method,
|
method: endpoints.GetCapabilityQuestions.method,
|
||||||
endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`,
|
endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`,
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getPartFromCapabilityQuestionAnswer(context, glassLocation) {
|
getPartFromCapabilityQuestionAnswer(context, glassLocation) {
|
||||||
const pageData = context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS);
|
const pageData = context.getters.pageData(
|
||||||
|
fmgPageValues.CAPABILITY_QUESTIONS
|
||||||
|
);
|
||||||
|
|
||||||
const part = pageData.partsOrQuestions.find(x => x.glassLocation === glassLocation).parts[0];
|
const part = pageData.partsOrQuestions.find(
|
||||||
const capabilityQuestionAnswers = context.getters.damage.capabilityQuestionAnswers;
|
(x) => x.glassLocation === glassLocation
|
||||||
const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find(x => x.glassLocation === glassLocation);
|
).parts[0];
|
||||||
|
const capabilityQuestionAnswers =
|
||||||
|
context.getters.damage.capabilityQuestionAnswers;
|
||||||
|
const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find(
|
||||||
|
(x) => x.glassLocation === glassLocation
|
||||||
|
);
|
||||||
|
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetPartFromCapabilityAnswer.method,
|
method: endpoints.GetPartFromCapabilityAnswer.method,
|
||||||
endpoint: endpoints.GetPartFromCapabilityAnswer.url,
|
endpoint: endpoints.GetPartFromCapabilityAnswer.url,
|
||||||
payload: {
|
payload: {
|
||||||
part,
|
part,
|
||||||
capabilityAnswerResults: capabilityQuestionAnswersForPart
|
capabilityAnswerResults: capabilityQuestionAnswersForPart,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Session API Actions
|
// Session API Actions
|
||||||
|
|
@ -809,21 +903,21 @@ export const actions = {
|
||||||
damage: {
|
damage: {
|
||||||
numberOfChips: damage.numberOfChips,
|
numberOfChips: damage.numberOfChips,
|
||||||
glassToReplace: damage.glassToReplace,
|
glassToReplace: damage.glassToReplace,
|
||||||
isRepair: damage.isRepair
|
isRepair: damage.isRepair,
|
||||||
},
|
},
|
||||||
customer: {
|
customer: {
|
||||||
emailAddress: order.customer.emailAddress,
|
emailAddress: order.customer.emailAddress,
|
||||||
},
|
},
|
||||||
lineItems: {
|
lineItems: {
|
||||||
glassParts: lineItems.glassParts
|
glassParts: lineItems.glassParts,
|
||||||
},
|
},
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
streetAddress: order.serviceLocation.address,
|
streetAddress: order.serviceLocation.address,
|
||||||
city: order.serviceLocation.city,
|
city: order.serviceLocation.city,
|
||||||
state: order.serviceLocation.state,
|
state: order.serviceLocation.state,
|
||||||
zipCode: order.serviceLocation.zipCode
|
zipCode: order.serviceLocation.zipCode,
|
||||||
},
|
},
|
||||||
referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place
|
referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place
|
||||||
referralDate: order.referralDate,
|
referralDate: order.referralDate,
|
||||||
accountNumber: order.accountNumber?.toString(),
|
accountNumber: order.accountNumber?.toString(),
|
||||||
existingPromoCode: null,
|
existingPromoCode: null,
|
||||||
|
|
@ -858,7 +952,6 @@ export const actions = {
|
||||||
|
|
||||||
// Vehicle
|
// Vehicle
|
||||||
saveVehicleYear(context, year) {
|
saveVehicleYear(context, year) {
|
||||||
|
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.year !== year) {
|
if (context.state.order.vehicle.year !== year) {
|
||||||
context.commit(storeMutations.UPDATE_MAKE, null);
|
context.commit(storeMutations.UPDATE_MAKE, null);
|
||||||
|
|
@ -880,7 +973,6 @@ export const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveVehicleMake(context, make) {
|
saveVehicleMake(context, make) {
|
||||||
|
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.make !== make) {
|
if (context.state.order.vehicle.make !== make) {
|
||||||
context.commit(storeMutations.UPDATE_MODEL, null);
|
context.commit(storeMutations.UPDATE_MODEL, null);
|
||||||
|
|
@ -901,7 +993,6 @@ export const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveVehicleModel(context, model) {
|
saveVehicleModel(context, model) {
|
||||||
|
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.model !== model) {
|
if (context.state.order.vehicle.model !== model) {
|
||||||
context.commit(storeMutations.UPDATE_STYLE, null);
|
context.commit(storeMutations.UPDATE_STYLE, null);
|
||||||
|
|
@ -938,20 +1029,32 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_STYLE, style);
|
context.commit(storeMutations.UPDATE_STYLE, style);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveVehicleDamage(context, { isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }) {
|
saveVehicleDamage(
|
||||||
|
context,
|
||||||
|
{ isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }
|
||||||
|
) {
|
||||||
const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort();
|
const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort();
|
||||||
const isGlassToReplaceTheSame = (context.state.order.damage.glassToReplace?.length === selectedGlassToReplace.length)
|
const isGlassToReplaceTheSame =
|
||||||
&& context.state.order.damage.glassToReplace
|
context.state.order.damage.glassToReplace?.length ===
|
||||||
|
selectedGlassToReplace.length &&
|
||||||
|
context.state.order.damage.glassToReplace
|
||||||
.slice()
|
.slice()
|
||||||
.sort()
|
.sort()
|
||||||
.every((obj, index) => obj.glassLocation === selectedGlassPassedInSorted[index].glassLocation && obj.glassName === selectedGlassPassedInSorted[index].glassName);
|
.every(
|
||||||
const isWindshieldRepairTheSame = isWindshieldRepair === context.state.order.damage.isRepair;
|
(obj, index) =>
|
||||||
const isChipCountTheSame = Array.isArray(selectedWindshieldChipCount) //TODO: fix the underlying components so this is never an array
|
obj.glassLocation ===
|
||||||
? selectedWindshieldChipCount[0] === context.state.order.damage.numberOfChips
|
selectedGlassPassedInSorted[index].glassLocation &&
|
||||||
: selectedWindshieldChipCount === context.state.order.damage.numberOfChips;
|
obj.glassName === selectedGlassPassedInSorted[index].glassName
|
||||||
|
);
|
||||||
|
const isWindshieldRepairTheSame =
|
||||||
|
isWindshieldRepair === context.state.order.damage.isRepair;
|
||||||
|
|
||||||
const isDamageChanging = !isGlassToReplaceTheSame || !isWindshieldRepairTheSame || (isWindshieldRepair && !isChipCountTheSame);
|
const isChipCountTheSame = selectedWindshieldChipCount === context.state.order.damage.numberOfChips;
|
||||||
|
|
||||||
|
const isDamageChanging =
|
||||||
|
!isGlassToReplaceTheSame ||
|
||||||
|
!isWindshieldRepairTheSame ||
|
||||||
|
(isWindshieldRepair && !isChipCountTheSame);
|
||||||
|
|
||||||
if (isDamageChanging) {
|
if (isDamageChanging) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
|
|
@ -959,13 +1062,22 @@ export const actions = {
|
||||||
|
|
||||||
// Save new values
|
// Save new values
|
||||||
context.commit(storeMutations.UPDATE_IS_REPAIR, isWindshieldRepair);
|
context.commit(storeMutations.UPDATE_IS_REPAIR, isWindshieldRepair);
|
||||||
context.commit(storeMutations.UPDATE_NUMBER_OF_CHIPS, isWindshieldRepair ? parseInt(selectedWindshieldChipCount) : null);
|
context.commit(
|
||||||
context.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, selectedGlassToReplace);
|
storeMutations.UPDATE_NUMBER_OF_CHIPS,
|
||||||
|
isWindshieldRepair ? parseInt(selectedWindshieldChipCount) : null
|
||||||
|
);
|
||||||
|
context.commit(
|
||||||
|
storeMutations.UPDATE_GLASS_TO_REPLACE,
|
||||||
|
selectedGlassToReplace
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Vin lookup
|
// Vin lookup
|
||||||
saveVinLookup(context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
|
saveVinLookup(
|
||||||
|
context,
|
||||||
|
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
||||||
|
) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
||||||
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
||||||
|
|
@ -980,10 +1092,15 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveRegistrationLicensePlateLookup(context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
|
saveRegistrationLicensePlateLookup(
|
||||||
|
context,
|
||||||
|
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
||||||
|
) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (registrationInfo?.licensePlate !== context.state.order.vehicle.registration?.licensePlate) {
|
if (
|
||||||
|
registrationInfo?.licensePlate !==
|
||||||
|
context.state.order.vehicle.registration?.licensePlate
|
||||||
|
) {
|
||||||
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
||||||
|
|
||||||
if (!isSelectedGlassAvailableForVehicle) {
|
if (!isSelectedGlassAvailableForVehicle) {
|
||||||
|
|
@ -996,10 +1113,25 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveRegistrationAddressLookup(context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) {
|
saveRegistrationAddressLookup(
|
||||||
|
context,
|
||||||
|
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
||||||
|
) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (registrationInfo?.address !== context.state.order.vehicle.registration?.address || registrationInfo?.city !== context.state.order.vehicle.registration?.city || registrationInfo?.state !== context.state.order.vehicle.registration?.state || registrationInfo?.zipCode !== context.state.order.vehicle.registration?.zipCode || registrationInfo?.firstName !== context.state.order.vehicle.registration?.firstName || registrationInfo?.lastName !== context.state.order.vehicle.registration?.lastName) {
|
if (
|
||||||
|
registrationInfo?.address !==
|
||||||
|
context.state.order.vehicle.registration?.address ||
|
||||||
|
registrationInfo?.city !==
|
||||||
|
context.state.order.vehicle.registration?.city ||
|
||||||
|
registrationInfo?.state !==
|
||||||
|
context.state.order.vehicle.registration?.state ||
|
||||||
|
registrationInfo?.zipCode !==
|
||||||
|
context.state.order.vehicle.registration?.zipCode ||
|
||||||
|
registrationInfo?.firstName !==
|
||||||
|
context.state.order.vehicle.registration?.firstName ||
|
||||||
|
registrationInfo?.lastName !==
|
||||||
|
context.state.order.vehicle.registration?.lastName
|
||||||
|
) {
|
||||||
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES);
|
||||||
|
|
||||||
if (!isSelectedGlassAvailableForVehicle) {
|
if (!isSelectedGlassAvailableForVehicle) {
|
||||||
|
|
@ -1014,72 +1146,141 @@ export const actions = {
|
||||||
},
|
},
|
||||||
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
||||||
// if part question answers have changed, reset subsequent question answers
|
// if part question answers have changed, reset subsequent question answers
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.partQuestionAnswers, "result");
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(partQuestionAnswersArray, "result")
|
context.getters.damage.partQuestionAnswers,
|
||||||
const havePartQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedPartQuestionAnswersArray.length ||
|
"result"
|
||||||
!sortedPreviousResultsArray?.every((x, i) => x.result === sortedPartQuestionAnswersArray[i].result);
|
);
|
||||||
|
const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(
|
||||||
|
partQuestionAnswersArray,
|
||||||
|
"result"
|
||||||
|
);
|
||||||
|
const havePartQuestionAnswersChanged =
|
||||||
|
sortedPreviousResultsArray?.length !==
|
||||||
|
sortedPartQuestionAnswersArray.length ||
|
||||||
|
!sortedPreviousResultsArray?.every(
|
||||||
|
(x, i) => x.result === sortedPartQuestionAnswersArray[i].result
|
||||||
|
);
|
||||||
|
|
||||||
if (havePartQuestionAnswersChanged) {
|
if (havePartQuestionAnswersChanged) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.VEHICLE_PARTS, data: null });
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null });
|
page: fmgPageValues.VEHICLE_PARTS,
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
|
data: null,
|
||||||
|
});
|
||||||
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
|
page: fmgPageValues.MOLDING_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
|
page: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_PART_QUESTION_ANSWERS,
|
||||||
|
partQuestionAnswersArray
|
||||||
|
);
|
||||||
},
|
},
|
||||||
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
|
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
|
||||||
const partsOrQuestionsDataToCompareWith = context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ?? context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)?.partsOrQuestions ?? [];
|
const partsOrQuestionsDataToCompareWith =
|
||||||
|
context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)
|
||||||
|
?.partsOrQuestions ??
|
||||||
|
context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)
|
||||||
|
?.partsOrQuestions ??
|
||||||
|
[];
|
||||||
|
|
||||||
function getAllPartNumbers(partsOrQuestions) {
|
function getAllPartNumbers(partsOrQuestions) {
|
||||||
return partsOrQuestions[0]?.parts
|
return partsOrQuestions[0]?.parts
|
||||||
? [...partsOrQuestions].map(glass => glass.parts).flat().map(part => part.partNumber).filter(partNumber => !partNumber.toUpperCase().includes("FEE")).sort().join(",")
|
? [...partsOrQuestions]
|
||||||
: []
|
.map((glass) => glass.parts)
|
||||||
|
.flat()
|
||||||
|
.map((part) => part.partNumber)
|
||||||
|
.filter((partNumber) => !partNumber.toUpperCase().includes("FEE"))
|
||||||
|
.sort()
|
||||||
|
.join(",")
|
||||||
|
: [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const previouslySelectedPartNumbers = getAllPartNumbers(partsOrQuestionsDataToCompareWith);
|
const previouslySelectedPartNumbers = getAllPartNumbers(
|
||||||
|
partsOrQuestionsDataToCompareWith
|
||||||
|
);
|
||||||
const currentlySelectedPartNumbers = getAllPartNumbers(matchedParts);
|
const currentlySelectedPartNumbers = getAllPartNumbers(matchedParts);
|
||||||
|
|
||||||
const haveSelectedVehiclePartsChanged = previouslySelectedPartNumbers !== currentlySelectedPartNumbers;
|
const haveSelectedVehiclePartsChanged =
|
||||||
|
previouslySelectedPartNumbers !== currentlySelectedPartNumbers;
|
||||||
|
|
||||||
if (haveSelectedVehiclePartsChanged) {
|
if (haveSelectedVehiclePartsChanged) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null });
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
|
page: fmgPageValues.MOLDING_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
|
page: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
|
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.moldingQuestionAnswers, "partNum");
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(moldingQuestionAnswers, "partNum");
|
context.getters.damage.moldingQuestionAnswers,
|
||||||
const haveMoldingQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length ||
|
"partNum"
|
||||||
!sortedPreviousResultsArray?.every((x, i) => x.partNum === sortedMoldingQuestionAnswersArray[i].partNum);
|
);
|
||||||
|
const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(
|
||||||
|
moldingQuestionAnswers,
|
||||||
|
"partNum"
|
||||||
|
);
|
||||||
|
const haveMoldingQuestionAnswersChanged =
|
||||||
|
sortedPreviousResultsArray?.length !==
|
||||||
|
sortedMoldingQuestionAnswersArray.length ||
|
||||||
|
!sortedPreviousResultsArray?.every(
|
||||||
|
(x, i) => x.partNum === sortedMoldingQuestionAnswersArray[i].partNum
|
||||||
|
);
|
||||||
|
|
||||||
if (haveMoldingQuestionAnswersChanged) {
|
if (haveMoldingQuestionAnswersChanged) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null);
|
||||||
context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null });
|
context.commit(storeMutations.UPDATE_PAGE_DATA, {
|
||||||
|
page: fmgPageValues.CAPABILITY_QUESTIONS,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS,
|
||||||
|
moldingQuestionAnswers
|
||||||
|
);
|
||||||
},
|
},
|
||||||
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
|
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(context.getters.damage.capabilityQuestionAnswers, "result");
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswers, "result");
|
context.getters.damage.capabilityQuestionAnswers,
|
||||||
const haveCapabilityQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedCapabilityQuestionAnswersArray.length ||
|
"result"
|
||||||
!sortedPreviousResultsArray?.every((x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result);
|
);
|
||||||
|
const sortedCapabilityQuestionAnswersArray =
|
||||||
|
sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswers, "result");
|
||||||
|
const haveCapabilityQuestionAnswersChanged =
|
||||||
|
sortedPreviousResultsArray?.length !==
|
||||||
|
sortedCapabilityQuestionAnswersArray.length ||
|
||||||
|
!sortedPreviousResultsArray?.every(
|
||||||
|
(x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result
|
||||||
|
);
|
||||||
|
|
||||||
if (haveCapabilityQuestionAnswersChanged) {
|
if (haveCapabilityQuestionAnswersChanged) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, capabilityQuestionAnswers);
|
context.commit(
|
||||||
|
storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS,
|
||||||
|
capabilityQuestionAnswers
|
||||||
|
);
|
||||||
},
|
},
|
||||||
// Misc order actions
|
// Misc order actions
|
||||||
saveServiceLocation(context, serviceLocationInfo) {
|
saveServiceLocation(context, serviceLocationInfo) {
|
||||||
|
|
@ -1091,7 +1292,6 @@ export const actions = {
|
||||||
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {
|
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
||||||
|
|
||||||
if (!isSelectedGlassAvailableForVehicle) {
|
if (!isSelectedGlassAvailableForVehicle) {
|
||||||
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES);
|
||||||
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES);
|
||||||
|
|
@ -1106,12 +1306,11 @@ export const actions = {
|
||||||
},
|
},
|
||||||
clearVin(context) {
|
clearVin(context) {
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default createStore({
|
export default createStore({
|
||||||
plugins: [createPersistedState()],
|
plugins: [createPersistedState()],
|
||||||
|
|
||||||
// IMPORTANT: Be VERY careful when modifying these fields for at least a few reasons:
|
// IMPORTANT: Be VERY careful when modifying these fields for at least a few reasons:
|
||||||
// * The CMS can reference the fields by name
|
// * The CMS can reference the fields by name
|
||||||
// * Return users may have a previous "version" of the model, and we don't want
|
// * Return users may have a previous "version" of the model, and we don't want
|
||||||
|
|
@ -1134,7 +1333,8 @@ function getHasRecalibrationPart(state) {
|
||||||
} else { // Has 'requiresRecalibration' but no 'recalibrationType' at all
|
} else { // Has 'requiresRecalibration' but no 'recalibrationType' at all
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else { // Does not have 'requiresRecalibration'
|
} else {
|
||||||
|
// Does not have 'requiresRecalibration'
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1143,11 +1343,8 @@ function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) {
|
||||||
if (!arrayOfObjects) return null;
|
if (!arrayOfObjects) return null;
|
||||||
|
|
||||||
return arrayOfObjects.sort((a, b) => {
|
return arrayOfObjects.sort((a, b) => {
|
||||||
if (a[propertyName] < b[propertyName])
|
if (a[propertyName] < b[propertyName]) return -1;
|
||||||
return -1;
|
else if (a[propertyName] > b[propertyName]) return 1;
|
||||||
else if (a[propertyName] > b[propertyName])
|
else return 0;
|
||||||
return 1;
|
});
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,6 @@ html {
|
||||||
&.list-button,
|
&.list-button,
|
||||||
&.list-card,
|
&.list-card,
|
||||||
&.list-card.list-button {
|
&.list-card.list-button {
|
||||||
// border: none;
|
|
||||||
color: $red;
|
color: $red;
|
||||||
input[type=checkbox]:focus + label,
|
input[type=checkbox]:focus + label,
|
||||||
input[type=radio]:focus + label {
|
input[type=radio]:focus + label {
|
||||||
|
|
@ -39,6 +38,17 @@ html {
|
||||||
box-shadow: 0 0 1px $red;
|
box-shadow: 0 0 1px $red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.grid-item {
|
||||||
|
input[type="radio"] {
|
||||||
|
+ label {
|
||||||
|
border: 1px solid $red;
|
||||||
|
&:hover {
|
||||||
|
background-color: $blue-100;
|
||||||
|
box-shadow: 0px 0px 0px 4px $red-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
&.ui-radio,
|
&.ui-radio,
|
||||||
&.ui-checkbox {
|
&.ui-checkbox {
|
||||||
input[type=checkbox],
|
input[type=checkbox],
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,17 @@
|
||||||
<button
|
<button
|
||||||
:aria-disabled="isDisabled"
|
:aria-disabled="isDisabled"
|
||||||
class="btn d-flex align-items-center py-3 px-4 delay"
|
class="btn d-flex align-items-center py-3 px-4 delay"
|
||||||
:class="[isPrimary ? 'btn-primary' : 'btn-secondary',isFloat ? 'float-end' : '', isLoaderDisplayed ? 'has-loader' : '']"
|
:class="[
|
||||||
@click="clicked"
|
isPrimary ? 'btn-primary' : 'btn-secondary',
|
||||||
>
|
isFloat ? 'float-end' : '',
|
||||||
|
isLoaderDisplayed ? 'has-loader' : '',
|
||||||
|
]"
|
||||||
|
@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:class="[this.loaderColor, this.loaderPosition]"
|
v-bind:class="[this.loaderColor, this.loaderPosition]" />
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -33,11 +35,16 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
removeLoader(){
|
removeLoader() {
|
||||||
this.isLoaderDisplayed = false;
|
this.isLoaderDisplayed = false;
|
||||||
},
|
},
|
||||||
clicked() {
|
clicked() {
|
||||||
this.pushEventToGA(this.$route.query[this.queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.buttonText, true);
|
this.pushEventToGA(
|
||||||
|
this.$route.query[this.queryStrings.FMG_PAGE],
|
||||||
|
this.GaActions.CLICKED,
|
||||||
|
this.buttonText,
|
||||||
|
true
|
||||||
|
);
|
||||||
if (!this.isDisabled) {
|
if (!this.isDisabled) {
|
||||||
this.isLoaderDisplayed = true;
|
this.isLoaderDisplayed = true;
|
||||||
this.$emit("click-event");
|
this.$emit("click-event");
|
||||||
|
|
@ -98,7 +105,8 @@ export default {
|
||||||
background: $blue-700;
|
background: $blue-700;
|
||||||
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;
|
||||||
}
|
}
|
||||||
&.delay {// fixes flicker while transitioning between states
|
&.delay {
|
||||||
|
// fixes flicker while transitioning between states
|
||||||
transition: background 0s 0s ease-in-out;
|
transition: background 0s 0s ease-in-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +145,8 @@ export default {
|
||||||
color: $white;
|
color: $white;
|
||||||
@include blue-gradient;
|
@include blue-gradient;
|
||||||
}
|
}
|
||||||
&.delay {// fixes flicker while transitioning between states
|
&.delay {
|
||||||
|
// fixes flicker while transitioning between states
|
||||||
transition: background 0s 0s ease-in-out;
|
transition: background 0s 0s ease-in-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,272 +1,202 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount, mount } from "@vue/test-utils";
|
||||||
import listButtonHorizontal from "./list-button-horizontal";
|
import listButtonHorizontal from "./list-button-horizontal";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
import { GaActions } from "@/constants/analytics";
|
import { GaActions } from "@/constants/analytics";
|
||||||
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
// TODO KO
|
describe("list-button-horizontal.vue", () => {
|
||||||
describe.skip("list-button-horizontal.vue", () => {
|
// TODO KO Have this moved out to somewhere shared
|
||||||
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
describe("Shared baseInputButton checks", () => {
|
||||||
// Act
|
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
// Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
isMultiSelect: true,
|
mockData: {
|
||||||
},
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
expect(input.attributes().type).toEqual("checkbox");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
|
||||||
const input = wrapper.find("input");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes().type).toEqual("checkbox");
|
// Assert
|
||||||
});
|
const input = wrapper.find("input");
|
||||||
|
expect(input.attributes().type).toEqual("radio");
|
||||||
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isMultiSelect: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
// TODO KO
|
||||||
const input = wrapper.find("input");
|
it.skip("Should emit button value on click", async () => {
|
||||||
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isRadioHorizontal: true,
|
||||||
|
buttonLabel: "Windshield",
|
||||||
|
value: "List Card Checkbox",
|
||||||
|
groupID: "radio-demo-1",
|
||||||
|
groupName: "radio 1",
|
||||||
|
buttonImage: "windshield-damage.svg",
|
||||||
|
isRequired: true,
|
||||||
|
isWide: false,
|
||||||
|
modelValue: ["List Card Checkbox"],
|
||||||
|
buttonID: "list-card-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes().type).toEqual("radio");
|
// Act
|
||||||
|
wrapper.vm.handleAnswerChange("test");
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["change"][0]).toEqual(["test"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should return primary label text (buttonID)", async () => {
|
describe("styling/UI", () => {
|
||||||
// Act
|
it("Should return screen reader text", async () => {
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
// Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
buttonID: "List Card Checkbox",
|
mockData: {
|
||||||
},
|
propsData: {
|
||||||
|
screenReaderOnlyText: "Screen Reader Only Text",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const paragraph = wrapper.find("span.sr-only");
|
||||||
|
|
||||||
|
expect(paragraph.text()).toEqual("Screen Reader Only Text");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return text alignment class", async () => {
|
||||||
const label = wrapper.find("label");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
textPosition: "text-center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(label.attributes().for).toEqual("List Card Checkbox");
|
// Assert
|
||||||
});
|
const paragraph = wrapper.find("span.m-0");
|
||||||
|
|
||||||
it("Should return screen reader text", async () => {
|
expect(paragraph.attributes("class")).toContain("text-center");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
screenReaderOnlyText: "Screen Reader Only Text",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return aria-required state", async () => {
|
||||||
const paragraph = wrapper.find("span.sr-only");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isRequired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(paragraph.text()).toEqual("Screen Reader Only Text");
|
// Assert
|
||||||
});
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
it("Should return text alignment class", async () => {
|
expect(input.attributes()["aria-required"]).toEqual("true");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
textPosition: "text-center",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("is cash or insurance button => has 'radio-fancy' class", () => {
|
||||||
const paragraph = wrapper.find("span.m-0");
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isCashOrInsurance: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(paragraph.attributes("class")).toContain("text-center");
|
// Assert
|
||||||
});
|
const label = wrapper.find("label");
|
||||||
|
|
||||||
it("Should return aria-required state", async () => {
|
expect(label.classes()).toContain("radio-fancy");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isRequired: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has buttonLabel => displays buttonLabel", () => {
|
||||||
const input = wrapper.find("input");
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes()["aria-required"]).toEqual("true");
|
// Assert
|
||||||
});
|
const content = wrapper.find(".list-button-horizontal-content");
|
||||||
|
expect(content.isVisible()).toBe(true);
|
||||||
it("Should return loader enabled true", async () => {
|
expect(content.text()).toContain("Surprise!");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
buttonLabelSubCopy: "Super duper surprise :)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const label = wrapper.find("label");
|
// Assert
|
||||||
|
const content = wrapper.find(".list-button-horizontal-content");
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
expect(content.isVisible()).toBe(true);
|
||||||
wrapper.vm.triggerButton();
|
expect(content.text()).toContain("Super duper surprise :)");
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
|
||||||
|
|
||||||
expect(loader.exists()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return loader color", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
loaderColor: "blue",
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has screenReaderOnlyText => displays screenReaderOnlyText", () => {
|
||||||
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
buttonLabelSubCopy: "Super duper surprise :)",
|
||||||
|
screenReaderOnlyText: "Tests are fun!"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const label = wrapper.find("label");
|
// Assert
|
||||||
|
const content = wrapper.find(".list-button-horizontal-content");
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
const screenReaderOnlyText = wrapper.find(".sr-only");
|
||||||
wrapper.vm.triggerButton();
|
expect(content.isVisible()).toBe(true);
|
||||||
|
expect(screenReaderOnlyText.exists()).toBe(true);
|
||||||
await nextTick();
|
expect(screenReaderOnlyText.text()).toContain("Tests are fun!");
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
|
||||||
|
|
||||||
expect(loader.attributes("class")).toContain("blue");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return loader position", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
loaderPosition: "right",
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
|
||||||
|
|
||||||
const label = wrapper.find("label");
|
|
||||||
|
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
|
||||||
wrapper.vm.triggerButton();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
|
||||||
|
|
||||||
expect(loader.attributes("class")).toContain("right");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should emit button value on click", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isRadioHorizontal: true,
|
|
||||||
buttonLabel: "Windshield",
|
|
||||||
value: "List Card Checkbox",
|
|
||||||
groupID: "radio-demo-1",
|
|
||||||
groupName: "radio 1",
|
|
||||||
buttonImage: "windshield-damage.svg",
|
|
||||||
isRequired: true,
|
|
||||||
isWide: false,
|
|
||||||
modelValue: ["List Card Checkbox"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
wrapper.vm.handleCheckChange();
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.emitted()["isCheckedChanged"][0]).toEqual([{value: "List Card Checkbox", checkValue: Boolean, buttonId: undefined, checkValue: false}]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should set checkValue data if selectedButtonIDs has value(s)", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isRadioHorizontal: true,
|
|
||||||
buttonLabel: "Windshield",
|
|
||||||
buttonID: "List Card Checkbox",
|
|
||||||
groupID: "radio-demo-1",
|
|
||||||
groupName: "radio 1",
|
|
||||||
buttonImage: "windshield-damage.svg",
|
|
||||||
isRequired: true,
|
|
||||||
isWide: false,
|
|
||||||
modelValue: ["List Card Checkbox"],
|
|
||||||
isMultiSelect: false,
|
|
||||||
value: "Car-Front",
|
|
||||||
selectedValues: ["Car-Front"]
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.vm.checkValue).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleInputChange is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleInputChange();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleCheckChange).toBeCalled;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should do nothing if isMultiSelect is true and handleKeyupArrow is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
isMultiSelect: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleKeyupArrow();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleKeyupArrow).toHaveReturned;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleKeyupArrow is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButtonHorizontal, {
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: false,
|
|
||||||
isMultiSelect: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleKeyupArrow();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleCheckChange).toBeCalled;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setupMocks({ mockData }) {
|
||||||
|
const wrapper = mount(listButtonHorizontal, {
|
||||||
|
...mockData,
|
||||||
|
propsData: {
|
||||||
|
...mockData.propsData,
|
||||||
|
groupName: "my-group",
|
||||||
|
modelValue: mockData.propsData?.isMultiSelect ? ["5"] : "5",
|
||||||
|
value: mockData.propsData?.isMultiSelect ? ["4"] : "4"
|
||||||
|
},
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
});
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
'list-group list-button-horizontal d-flex flex-column w-100',
|
'list-group list-button-horizontal d-flex flex-column w-100',
|
||||||
{ 'radio-fancy': additionalData?.isCashOrInsurance },
|
{ 'radio-fancy': additionalData?.isCashOrInsurance },
|
||||||
]"
|
]"
|
||||||
@buttonClicked="handleAnswerChange">
|
v-model="selectedValue">
|
||||||
<div
|
<div
|
||||||
class="list-button-horizontal-content d-flex flex-column justify-content-center p-3">
|
class="list-button-horizontal-content d-flex flex-column justify-content-center p-3">
|
||||||
<span class="m-0" :class="textPosition">
|
<span class="m-0" :class="textPosition">
|
||||||
|
|
|
||||||
|
|
@ -1,264 +1,262 @@
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount, mount } from "@vue/test-utils";
|
||||||
import listButton from "./list-button";
|
import listButton from "./list-button";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
import { GaActions } from "@/constants/analytics";
|
import { GaActions } from "@/constants/analytics";
|
||||||
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
// TODO KO
|
// TODO KO
|
||||||
describe.skip("list-button.vue", () => {
|
describe.skip("list-button.vue", () => {
|
||||||
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
describe("loader", () => {
|
||||||
// Act
|
it("selectingInitiatesLoad is true and answer is changed => show the loader", async () => {
|
||||||
const wrapper = shallowMount(listButton, {
|
// Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
isMultiSelect: true,
|
mockData: {
|
||||||
},
|
global: {
|
||||||
|
mocks: {
|
||||||
|
$route: { query: { fmgPage: "page-name" } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
propsData: {
|
||||||
|
selectingInitiatesLoad: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
wrapper.vm.handleAnswerChange("something");
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const loader = wrapper.findComponent({ name: "loader" });
|
||||||
|
expect(loader.exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return loader color", async () => {
|
||||||
const input = wrapper.find("input");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
$route: { query: { fmgPage: "page-name" } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
propsData: {
|
||||||
|
loaderColor: "blue",
|
||||||
|
selectingInitiatesLoad: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes().type).toEqual("checkbox");
|
// Act
|
||||||
});
|
wrapper.vm.handleAnswerChange("something");
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
|
// Assert
|
||||||
// Act
|
const loader = wrapper.findComponent({ name: "loader" });
|
||||||
const wrapper = shallowMount(listButton, {
|
expect(loader.attributes("class")).toContain("blue");
|
||||||
propsData: {
|
|
||||||
isMultiSelect: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return loader position", async () => {
|
||||||
const input = wrapper.find("input");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
global: {
|
||||||
|
mocks: {
|
||||||
|
$route: { query: { fmgPage: "page-name" } },
|
||||||
|
GaActions: GaActions,
|
||||||
|
pushEventToGA: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
propsData: {
|
||||||
|
loaderPosition: "right",
|
||||||
|
selectingInitiatesLoad: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes().type).toEqual("radio");
|
// Act
|
||||||
|
wrapper.vm.handleAnswerChange("test");
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const loader = wrapper.findComponent({ name: "loader" });
|
||||||
|
expect(loader.attributes("class")).toContain("right");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should return primary label text (buttonID)", async () => {
|
describe("baseInputButton checks", () => {
|
||||||
// Act
|
it("Should return input type checkbox if isMultiSelect is true", async () => {
|
||||||
const wrapper = shallowMount(listButton, {
|
// Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
buttonID: "List Card Checkbox",
|
mockData: {
|
||||||
},
|
propsData: {
|
||||||
|
isMultiSelect: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
expect(input.attributes().type).toEqual("checkbox");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return input type radio if isMultiSelect is false or not specified", async () => {
|
||||||
const label = wrapper.find("label");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isMultiSelect: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(label.attributes().for).toEqual("List Card Checkbox");
|
// Assert
|
||||||
});
|
const input = wrapper.find("input");
|
||||||
|
expect(input.attributes().type).toEqual("radio");
|
||||||
it("Should return screen reader text", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
screenReaderOnlyText: "Screen Reader Only Text",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should emit button value on click", async () => {
|
||||||
const paragraph = wrapper.find("span.sr-only");
|
// Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isRadioHorizontal: true,
|
||||||
|
buttonLabel: "Windshield",
|
||||||
|
value: "List Card Checkbox",
|
||||||
|
groupID: "radio-demo-1",
|
||||||
|
groupName: "radio 1",
|
||||||
|
buttonImage: "windshield-damage.svg",
|
||||||
|
isRequired: true,
|
||||||
|
isWide: false,
|
||||||
|
modelValue: ["List Card Checkbox"],
|
||||||
|
buttonID: "list-card-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(paragraph.text()).toEqual("Screen Reader Only Text");
|
// Act
|
||||||
|
wrapper.vm.handleAnswerChange("test");
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()["change"][0]).toEqual(["test"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should return text alignment class", async () => {
|
describe("styling/UI", () => {
|
||||||
// Act
|
test("has buttonLabel => displays buttonLabel", () => {
|
||||||
const wrapper = shallowMount(listButton, {
|
// Arrange/Act
|
||||||
propsData: {
|
const { wrapper } = setupMocks({
|
||||||
textPosition: "text-center",
|
mockData: {
|
||||||
},
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const content = wrapper.find(".list-button-content");
|
||||||
|
expect(content.isVisible()).toBe(true);
|
||||||
|
expect(content.text()).toContain("Surprise!");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has buttonLabelSubCopy => displays buttonLabelSubCopy", () => {
|
||||||
const paragraph = wrapper.find("span.m-0");
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
buttonLabelSubCopy: "Super duper surprise :)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(paragraph.attributes("class")).toContain("text-center");
|
// Assert
|
||||||
});
|
const content = wrapper.find(".list-button-content");
|
||||||
|
expect(content.isVisible()).toBe(true);
|
||||||
it("Should return aria-required state", async () => {
|
expect(content.text()).toContain("Super duper surprise :)");
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
isRequired: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
test("has screenReaderOnlyText => displays screenReaderOnlyText", () => {
|
||||||
const input = wrapper.find("input");
|
// Arrange/Act
|
||||||
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "Surprise!",
|
||||||
|
buttonLabelSubCopy: "Super duper surprise :)",
|
||||||
|
screenReaderOnlyText: "Tests are fun!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(input.attributes()["aria-required"]).toEqual("true");
|
// Assert
|
||||||
});
|
const content = wrapper.find(".list-button-content");
|
||||||
|
const screenReaderOnlyText = wrapper.find(".sr-only");
|
||||||
it("Should return loader enabled true", async () => {
|
expect(content.isVisible()).toBe(true);
|
||||||
// Act
|
expect(screenReaderOnlyText.exists()).toBe(true);
|
||||||
const wrapper = shallowMount(listButton, {
|
expect(screenReaderOnlyText.text()).toContain("Tests are fun!");
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return screen reader text", async () => {
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
// Act
|
||||||
wrapper.vm.triggerButton();
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
screenReaderOnlyText: "Screen Reader Only Text",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
await nextTick();
|
// Assert
|
||||||
|
const paragraph = wrapper.find("span.sr-only");
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
expect(paragraph.text()).toEqual("Screen Reader Only Text");
|
||||||
|
|
||||||
expect(loader.exists()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return loader color", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
loaderColor: "blue",
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return text alignment class", async () => {
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
// Act
|
||||||
wrapper.vm.triggerButton();
|
const { wrapper } = setupMocks({
|
||||||
await nextTick();
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
textPosition: "text-center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
// Assert
|
||||||
|
const paragraph = wrapper.find("span.m-0");
|
||||||
|
|
||||||
expect(loader.attributes("class")).toContain("blue");
|
expect(paragraph.attributes("class")).toContain("text-center");
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return loader position", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
global: {
|
|
||||||
mocks: {
|
|
||||||
'$route': { query: { fmgPage: 'page-name' } },
|
|
||||||
GaActions: GaActions,
|
|
||||||
pushEventToGA: jest.fn(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
propsData: {
|
|
||||||
loaderPosition: "right",
|
|
||||||
selectingInitiatesLoad: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
it("Should return aria-required state", async () => {
|
||||||
wrapper.vm.handleCheckChange = jest.fn();
|
// Act
|
||||||
wrapper.vm.triggerButton();
|
const { wrapper } = setupMocks({
|
||||||
|
mockData: {
|
||||||
|
propsData: {
|
||||||
|
isRequired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
await nextTick();
|
// Assert
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
const loader = wrapper.find("loader-stub");
|
expect(input.attributes()["aria-required"]).toEqual("true");
|
||||||
|
|
||||||
expect(loader.attributes("class")).toContain("right");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should emit button value on click", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
isRadioHorizontal: true,
|
|
||||||
buttonLabel: "Windshield",
|
|
||||||
value: "List Card Checkbox",
|
|
||||||
groupID: "radio-demo-1",
|
|
||||||
groupName: "radio 1",
|
|
||||||
buttonImage: "windshield-damage.svg",
|
|
||||||
isRequired: true,
|
|
||||||
isWide: false,
|
|
||||||
modelValue: ["List Card Checkbox"],
|
|
||||||
buttonID: 'list-card-id'
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.vm.handleCheckChange();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.emitted()["isCheckedChanged"][0]).toEqual([{value: "List Card Checkbox", checkValue: false, buttonId: 'list-card-id'}]);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should set checkValue data if selectedButtonIDs has value(s)", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
isRadioHorizontal: true,
|
|
||||||
buttonLabel: "Windshield",
|
|
||||||
buttonID: "List Card Checkbox",
|
|
||||||
groupID: "radio-demo-1",
|
|
||||||
groupName: "radio 1",
|
|
||||||
buttonImage: "windshield-damage.svg",
|
|
||||||
isRequired: true,
|
|
||||||
isWide: false,
|
|
||||||
modelValue: ["List Card Checkbox"],
|
|
||||||
selectedValues: "Car-Front"
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.componentVM.checkValue).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleInputChange is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleInputChange();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleCheckChange).toBeCalled;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should do nothing if isMultiSelect is true and handleKeyupArrow is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
isMultiSelect: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleKeyupArrow();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleKeyupArrow).toHaveReturned;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should run handleCheckChange if selectingInitiatesLoad is false and handleKeyupArrow is triggered", async () => {
|
|
||||||
// Act
|
|
||||||
const wrapper = shallowMount(listButton, {
|
|
||||||
propsData: {
|
|
||||||
selectingInitiatesLoad: false,
|
|
||||||
isMultiSelect: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
wrapper.vm.handleKeyupArrow();
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(wrapper.vm.handleCheckChange).toBeCalled;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setupMocks({ mockData }) {
|
||||||
|
const wrapper = mount(listButton, {
|
||||||
|
...mockData,
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
});
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<baseInputButton
|
<baseInputButton
|
||||||
v-bind="$props"
|
v-bind="$props"
|
||||||
buttonWrapperClasses="list-group list-button rounded-3 d-flex flex-column w-100 mb-2"
|
buttonWrapperClasses="list-group list-button rounded-3 d-flex flex-column w-100 mb-2"
|
||||||
@buttonClicked="handleAnswerChange">
|
v-model="selectedValue">
|
||||||
<div
|
<div
|
||||||
:aria-label="buttonLabel"
|
:aria-label="buttonLabel"
|
||||||
class="list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
class="list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ describe("list-card.vue", () => {
|
||||||
groupID: "checkbox-demo-1",
|
groupID: "checkbox-demo-1",
|
||||||
groupName: "Checkbox 1",
|
groupName: "Checkbox 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -32,6 +33,7 @@ describe("list-card.vue", () => {
|
||||||
groupID: "radio-demo-1",
|
groupID: "radio-demo-1",
|
||||||
groupName: "radio 1",
|
groupName: "radio 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -51,6 +53,7 @@ describe("list-card.vue", () => {
|
||||||
groupName: "radio 1",
|
groupName: "radio 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
buttonLabelSubCopy: "Test",
|
buttonLabelSubCopy: "Test",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -70,6 +73,7 @@ describe("list-card.vue", () => {
|
||||||
groupName: "radio 1",
|
groupName: "radio 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
buttonLabelSubCopy: "Test",
|
buttonLabelSubCopy: "Test",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -89,6 +93,7 @@ describe("list-card.vue", () => {
|
||||||
groupName: "radio 1",
|
groupName: "radio 1",
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -110,6 +115,7 @@ describe("list-card.vue", () => {
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
isWide: true,
|
isWide: true,
|
||||||
buttonLabelSubCopy: "",
|
buttonLabelSubCopy: "",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -134,6 +140,7 @@ describe("list-card.vue", () => {
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
isWide: true,
|
isWide: true,
|
||||||
buttonLabelSubCopy: "Button Subcopy",
|
buttonLabelSubCopy: "Button Subcopy",
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -159,6 +166,7 @@ describe("list-card.vue", () => {
|
||||||
buttonImage: "windshield-damage.svg",
|
buttonImage: "windshield-damage.svg",
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
isWide: false,
|
isWide: false,
|
||||||
|
value: "test value",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
'list-card w-100 rounded-3 d-flex align-items-center h-100',
|
'list-card w-100 rounded-3 d-flex align-items-center h-100',
|
||||||
{ horizontal: isWide },
|
{ horizontal: isWide },
|
||||||
]"
|
]"
|
||||||
@buttonClicked="handleAnswerChange">
|
v-model="selectedValue">
|
||||||
<div
|
<div
|
||||||
class="d-flex w-100 align-items-center px-2 h-100 list-card-content"
|
class="d-flex w-100 align-items-center px-2 h-100 list-card-content"
|
||||||
:class="labelClasses">
|
:class="labelClasses">
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,16 @@ import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
describe("radio.vue", () => {
|
describe("radio.vue", () => {
|
||||||
it("Should have correct group name", async () => {
|
it("Should have correct group name", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
let { wrapper } = setupMocks({});
|
let { wrapper } = setupMocks({
|
||||||
|
mountOptionsMockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "radio-button-test",
|
||||||
|
value: "test value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.setProps({
|
|
||||||
groupName: "radio-button-test",
|
|
||||||
});
|
|
||||||
const input = wrapper.find("input");
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -20,12 +24,16 @@ describe("radio.vue", () => {
|
||||||
|
|
||||||
it("Should have correct label text", async () => {
|
it("Should have correct label text", async () => {
|
||||||
// Act
|
// Act
|
||||||
let { wrapper } = setupMocks({});
|
let { wrapper } = setupMocks({
|
||||||
|
mountOptionsMockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "label text",
|
||||||
|
value: "test value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
await wrapper.setProps({
|
|
||||||
buttonLabel: "label text",
|
|
||||||
});
|
|
||||||
const paragraph = wrapper.find("p");
|
const paragraph = wrapper.find("p");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -39,6 +47,7 @@ describe("radio.vue", () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
await wrapper.setProps({
|
await wrapper.setProps({
|
||||||
screenReaderOnlyText: "screenreader text",
|
screenReaderOnlyText: "screenreader text",
|
||||||
|
value: "test value",
|
||||||
});
|
});
|
||||||
const paragraph = wrapper.find(".sr-only");
|
const paragraph = wrapper.find(".sr-only");
|
||||||
|
|
||||||
|
|
@ -48,13 +57,10 @@ describe("radio.vue", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function setupMocks({ mountOptionsMockData = {} }) {
|
function setupMocks({ mountOptionsMockData = {} }) {
|
||||||
const wrapper = mount(
|
const wrapper = mount(radio, {
|
||||||
radio,
|
...mountOptionsMockData,
|
||||||
getMountOptions({
|
mixins: [inputButtonWrapperMixin],
|
||||||
...mountOptionsMockData,
|
});
|
||||||
mixins: [inputButtonWrapperMixin],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
v-bind="$props"
|
v-bind="$props"
|
||||||
buttonWrapperClasses="ui-radio form-check"
|
buttonWrapperClasses="ui-radio form-check"
|
||||||
inputClasses="form-check-input"
|
inputClasses="form-check-input"
|
||||||
@buttonClicked="handleAnswerChange">
|
v-model="selectedValue">
|
||||||
<div class="d-flex align-items-start form-check-label">
|
<div class="d-flex align-items-start form-check-label">
|
||||||
<p v-if="buttonLabel" class="m-0">{{ buttonLabel }}</p>
|
<p v-if="buttonLabel" class="m-0">{{ buttonLabel }}</p>
|
||||||
<span v-if="screenReaderOnlyText" class="sr-only">{{
|
<span v-if="screenReaderOnlyText" class="sr-only">{{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue