diff --git a/jest.config.js b/jest.config.js index efec3da84..87d9800fb 100644 --- a/jest.config.js +++ b/jest.config.js @@ -22,6 +22,8 @@ module.exports = { "!src/common-components/funnel-header/menu-modal/**/*.vue", "!src/layouts/schedule/helpers/schedule-helper.js", // Temp test exclusion while in development "!src/layouts/review/*.vue", // Temp test exclusion while in development + "!src/layouts/payment/*.vue", // Temp test exclusion while in development + "!src/layouts/payment-pia-return/*.vue", // Temp test exclusion while in development // END ], // ! means exclude from coverage. testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], diff --git a/src/digital-components/button-question/button-question.vue b/src/digital-components/button-question/button-question.vue index e4c997f6d..0ac7e2863 100644 --- a/src/digital-components/button-question/button-question.vue +++ b/src/digital-components/button-question/button-question.vue @@ -92,6 +92,7 @@ import listButton from "@/ux-components/list-button/list-button"; import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal"; import listCard from "@/ux-components/list-card/list-card"; import radio from "@/ux-components/radio/radio"; +import checkbox from "@/ux-components/checkbox/checkbox"; import { useField, ErrorMessage } from "vee-validate"; import { queryStrings } from "@/constants/query-strings"; @@ -209,6 +210,9 @@ export default { case "radio": classes = "ui-radio d-flex"; break; + case "checkbox": + classes = "ui-checkbox d-flex"; + break; case "servicePackageRadio": classes = "package-main"; break; @@ -317,6 +321,7 @@ export default { listCard, ErrorMessage, radio, + checkbox, }, }; diff --git a/src/fmg-components/add-vaps-modal-buttons/add-vaps-modal-buttons.vue b/src/fmg-components/add-vaps-modal-buttons/add-vaps-modal-buttons.vue deleted file mode 100644 index 11ee74e32..000000000 --- a/src/fmg-components/add-vaps-modal-buttons/add-vaps-modal-buttons.vue +++ /dev/null @@ -1,108 +0,0 @@ - - - diff --git a/src/layouts/payment-method/add-vaps-modal-buttons/add-vaps-modal-buttons.vue b/src/layouts/payment-method/add-vaps-modal-buttons/add-vaps-modal-buttons.vue index 0c7976ea8..c502fb165 100644 --- a/src/layouts/payment-method/add-vaps-modal-buttons/add-vaps-modal-buttons.vue +++ b/src/layouts/payment-method/add-vaps-modal-buttons/add-vaps-modal-buttons.vue @@ -26,30 +26,24 @@ v-if="wipersModal" @footer-button-action="addWipersToCart('WipersModal', wipersModal)" footerButtonActionName="footer-button-action"> -
-
- -

+${{ wipersModal.totalFrontPrice }}

-
-
- -

+${{ wipersModal.totalRearPrice }}

-
+
+
-
+

+${{ wipersModal.totalFrontPrice }}

-
+

+${{ wipersModal.totalRearPrice }}

@@ -62,12 +56,17 @@ import buttonQuestion from "@/digital-components/button-question/button-question"; import addVapsButton from "./add-vaps-button/add-vaps-button"; import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal"; -import checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question"; // SUPPORTING import { partTypeStrings } from "@/constants/part-type-strings"; +import { defineRule } from "vee-validate"; +import { required } from "@/helpers/validation-rules"; +import { errorMessages } from "@/constants/error-messages"; -const wipersToDisplayStrings = { +// DEFINE VALIDATION RULES +defineRule("checkbox-required", required(errorMessages.OPTION_REQUIRED)); + +const wipersOfferedStrings = { FRONT: "FRONT", REAR: "REAR", BOTH: "BOTH", @@ -83,15 +82,18 @@ export default { data() { return { addVapsButton: addVapsButton, - selectedFrontWipers: false, - selectedRearWipers: false, - wipersToDisplay: null, + wipersOffered: null, + isModalOpened: false, + selectedWipers: this.getSelectedWipers(), }; }, methods: { openModal(modalName) { this.$refs[modalName].openModal(); }, + closeModal(modalName) { + this.$refs[modalName].closeModal(); + }, addRainDefenseToCart(modalName, part) { const alreadyInCart = this.currentCartItems.vaps.some((item) => { return item.partType === part.partType; @@ -99,9 +101,11 @@ export default { if (!alreadyInCart) { this.currentCartItems.vaps.push(part); } - this.$refs[modalName].closeModal(); + this.closeModal(modalName); }, addWipersToCart(modalName, part) { + const itemsForCart = []; + const frontWipersAlreadyInCart = this.currentCartItems.vaps.some((item) => { return item.partType === part.frontWiperLineItems[0].partType; }); @@ -109,36 +113,43 @@ export default { return item.partType === part.rearWiperLineItems[0]?.partType; }); - if (this.wipersToDisplay === wipersToDisplayStrings.FRONT) { - this.selectedFrontWipers = true; // set as true if front wipers is only option + if (this.wipersOffered === wipersOfferedStrings.BOTH) { + this.selectedWipers.forEach((wiper) => { + itemsForCart.push(wiper); + }); + } else { + if ( + !frontWipersAlreadyInCart && + this.wipersOffered === wipersOfferedStrings.FRONT + ) { + itemsForCart.push(wipersOfferedStrings.FRONT); + } + if (!rearWipersAlreadyInCart && this.wipersOffered === wipersOfferedStrings.REAR) { + itemsForCart.push(wipersOfferedStrings.REAR); + } } - if (this.wipersToDisplay === wipersToDisplayStrings.REAR) { - this.selectedRearWipers = true; // set as true if rear wipers is only option - } - if (!frontWipersAlreadyInCart && this.selectedFrontWipers) { - if (part.frontWiperLineItems) { - // for wipers, a "combined" part (frontWiperLineItems) + + itemsForCart.forEach((type) => { + if (type === wipersOfferedStrings.FRONT) { part.frontWiperLineItems.forEach((part) => { this.currentCartItems.vaps.push(part); }); } - } - if (!rearWipersAlreadyInCart && this.selectedRearWipers) { - if (part.rearWiperLineItems) { + if (type === wipersOfferedStrings.REAR) { part.rearWiperLineItems.forEach((part) => { this.currentCartItems.vaps.push(part); }); } - } - this.$refs[modalName].closeModal(); + }); - if (this.wipersToDisplay === wipersToDisplayStrings.BOTH) { - this.selectedFrontWipers = false; // set as false if both options are given - this.selectedRearWipers = false; // set as false if both options are given - } + this.closeModal(modalName); + this.selectedWipers; }, - updateWipersToDisplay(value) { - this.wipersToDisplay = value; + updateWipersOffered(value) { + this.wipersOffered = value; + }, + getSelectedWipers() { + return null; }, }, computed: { @@ -229,31 +240,72 @@ export default { ]; prices.sort((a, b) => a - b); modalData.SubText = "+$" + prices[0] + " - $" + prices[prices.length - 1]; - this.updateWipersToDisplay(wipersToDisplayStrings.BOTH); + this.updateWipersOffered(wipersOfferedStrings.BOTH); buttons.push(modalData); } else { // NO FRONT WIPERS IN CART; SHOW ONLY FRONT WIPERS BUTTON modalData.SubText = "+$" + this.wipersModal?.totalFrontPrice; - this.updateWipersToDisplay(wipersToDisplayStrings.FRONT); + this.updateWipersOffered(wipersOfferedStrings.FRONT); buttons.push(modalData); } } else if (!rearWipersInCart && this.wipersModal?.rearWiperLineItems.length > 0) { // NO REAR WIPERS IN CART; SHOW ONLY REAR WIPERS BUTTON modalData.SubText = "+$" + this.wipersModal?.totalRearPrice; - this.updateWipersToDisplay(wipersToDisplayStrings.REAR); + this.updateWipersOffered(wipersOfferedStrings.REAR); buttons.push(modalData); } return buttons; }, - wipersToDisplayStrings() { - return wipersToDisplayStrings; + wipersOfferedStrings() { + return wipersOfferedStrings; + }, + wipersOptions() { + const wipersOptions = []; + const wipersFrontCopy = this.getCmsContent( + "AddFrontBladesQuestionWidget", + "QuestionText" + ); + const wipersRearCopy = this.getCmsContent( + "AddRearBladesQuestionWidget", + "QuestionText" + ); + const frontWipersLineItems = this.wipersModal.frontWiperLineItems; + const rearWipersLineItems = this.wipersModal.rearWiperLineItems; + + if (frontWipersLineItems) { + const wipersOption = { + buttonLabel: wipersFrontCopy, + groupName: "wipers-options", + value: wipersOfferedStrings.FRONT, + buttonLabelSubCopy: "buttonLabelSubCopy", + buttonBodyCopy: "buttonBodyCopy", + buttonAuxillaryCopy: "buttonAuxillaryCopy", + buttonFooterCopy: "buttonFooterCopy", + additionalButtonData: "+$" + this.wipersModal.totalFrontPrice, + }; + wipersOptions.push(wipersOption); + } + if (rearWipersLineItems) { + const wipersOption = { + buttonLabel: wipersRearCopy, + groupName: "wipers-options", + value: wipersOfferedStrings.REAR, + buttonLabelSubCopy: "buttonLabelSubCopy", + buttonBodyCopy: "buttonBodyCopy", + buttonAuxillaryCopy: "buttonAuxillaryCopy", + buttonFooterCopy: "buttonFooterCopy", + additionalButtonData: "+$" + this.wipersModal.totalRearPrice, + }; + wipersOptions.push(wipersOption); + } + + return wipersOptions; }, }, components: { buttonQuestion, contentGroupModal, - checkboxQuestion, }, }; @@ -286,26 +338,31 @@ export default { text-align: center; } .wiper-options { - & > div { - display: flex; - justify-content: space-between; - margin-bottom: 1rem; + .ui-checkbox { + display: block; - &:last-child { - margin-bottom: 0; + & > div.col { + margin-bottom: 1rem; + + &:last-child { + margin-bottom: 0; + } } + .checkbox { + display: flex; + justify-content: space-between; - .form-check { - margin-bottom: 0; + .additional-button-data { + font-size: 0.875rem; + line-height: 1.75; + padding-left: 0.5rem; + color: $green; + } } } p { margin-bottom: 0; - } - p.price { - font-size: 0.875rem; - padding-left: 0.5rem; - color: $green; + line-height: 1.75; } } } diff --git a/src/ux-components/checkbox/checkbox.spec.js b/src/ux-components/checkbox/checkbox.spec.js new file mode 100644 index 000000000..7aa72b718 --- /dev/null +++ b/src/ux-components/checkbox/checkbox.spec.js @@ -0,0 +1,66 @@ +import { mount } from "@vue/test-utils"; +import checkbox from "./checkbox"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; + +describe("checkbox.vue", () => { + it("Should have correct group name", async () => { + // Arrange + let { wrapper } = setupMocks({ + mountOptionsMockData: { + propsData: { + groupName: "checkbox-button-test", + value: "test value", + }, + }, + }); + + // Act + const input = wrapper.find("input"); + + // Assert + expect(input.attributes().name).toEqual("checkbox-button-test"); + }); + + it("Should have correct label text", async () => { + // Act + let { wrapper } = setupMocks({ + mountOptionsMockData: { + propsData: { + buttonLabel: "label text", + value: "test value", + }, + }, + }); + + // Arrange + const paragraph = wrapper.find("p"); + + // Assert + expect(paragraph.text()).toEqual("label text"); + }); + + it("Should have correct screenreader-only text", async () => { + // Act + let { wrapper } = setupMocks({}); + + // Arrange + await wrapper.setProps({ + screenReaderOnlyText: "screenreader text", + value: "test value", + }); + const paragraph = wrapper.find(".sr-only"); + + // Assert + expect(paragraph.text()).toEqual("screenreader text"); + }); +}); + +function setupMocks({ mountOptionsMockData = {} }) { + const wrapper = mount(checkbox, { + ...mountOptionsMockData, + mixins: [inputButtonWrapperMixin], + }); + + return { wrapper }; +} diff --git a/src/ux-components/checkbox/checkbox.vue b/src/ux-components/checkbox/checkbox.vue new file mode 100644 index 000000000..9c02b7b99 --- /dev/null +++ b/src/ux-components/checkbox/checkbox.vue @@ -0,0 +1,74 @@ + + + + +