diff --git a/src/layouts/scheduling/scheduling.spec.js b/src/layouts/scheduling/scheduling.spec.js index 33b02e753..d6daabebb 100644 --- a/src/layouts/scheduling/scheduling.spec.js +++ b/src/layouts/scheduling/scheduling.spec.js @@ -28,6 +28,7 @@ jest.mock("@/store", () => ({ damage: { isRepair: false }, lineItems: { glassParts: [] }, policy: { isItac: false, isNoComp: false }, + isRecalAcknowledgedForScheduling: "", }, lineItems: { supportingItems: [] }, applicationUser: { @@ -84,6 +85,7 @@ function setupMocks({ isAppleBrowser = false } = {}) { CLICKED_FORWARD: "clickedForward", CLICKED_FORWARD_WITH_MOBILE_SERVICE: "clickedForwardWithMobileService", CLICKED_BACK: "clickedBack", + ZIP_CODE_CHANGED_RECAL_ACK: "ZIP_CODE_CHANGED_RECAL_ACK", }; }, pageName() { @@ -283,6 +285,36 @@ describe("scheduling.vue", () => { expect(wrapper.vm.$refs.schedulingZipSearch.focusZipInput).toHaveBeenCalled(); wrapper.unmount(); }); + + test("navigates to service-zip when zip changes and recal acknowledgement applies", async () => { + store.getters.order.lineItems = { + glassParts: [ + { + partType: "WINDSHIELD", + requiresRecalibration: true, + canSafeliteRecalibrate: false, + }, + ], + }; + try { + const { wrapper } = setupMocks(); + await wrapper.setData({ + isRecalAcknowledgedForScheduling: "", + isLoadingDates: false, + }); + + await wrapper.vm.onZipSearched({ zipCode: "44101", billToAccountNumber: "87291" }); + + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith( + "ZIP_CODE_CHANGED_RECAL_ACK", + "scheduling" + ); + expect(wrapper.vm.isLoadingDates).toBe(false); + wrapper.unmount(); + } finally { + store.getters.order.lineItems = { glassParts: [] }; + } + }); }); describe("forwardButtonAction", () => { @@ -413,6 +445,56 @@ describe("scheduling.vue", () => { }); }); + describe("forwardButtonAction (recal acknowledgement)", () => { + test("opens recal modal and does not navigate when required", async () => { + store.getters.order.lineItems = { + glassParts: [ + { + partType: "WINDSHIELD", + requiresRecalibration: true, + canSafeliteRecalibrate: false, + }, + ], + }; + const { wrapper } = setupMocks(); + wrapper.vm.$refs.navbar.removeLoader = jest.fn(); + wrapper.vm.$refs.recalAckModal.openModal = jest.fn(); + await wrapper.setData({ isRecalAcknowledgedForScheduling: "" }); + + await wrapper.vm.forwardButtonAction(); + + expect(wrapper.vm.$refs.recalAckModal.openModal).toHaveBeenCalled(); + expect(wrapper.vm.$router.navigateWithSaving).not.toHaveBeenCalled(); + wrapper.unmount(); + store.getters.order.lineItems = { glassParts: [] }; + }); + + test("navigates forward after recal acknowledgement is saved", async () => { + const { wrapper } = setupMocks(); + await wrapper.setData({ isRecalAcknowledgedForScheduling: "Yes" }); + + await wrapper.vm.forwardButtonAction(); + + expect(store.dispatch).toHaveBeenCalledWith( + "saveIsRecalAcknowledgedForScheduling", + "Yes" + ); + expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled(); + wrapper.unmount(); + }); + + test("onRecalAcknowledged sets acknowledgement and continues forward", async () => { + const { wrapper } = setupMocks(); + wrapper.vm.forwardButtonAction = jest.fn(); + + wrapper.vm.onRecalAcknowledged("Yes"); + + expect(wrapper.vm.isRecalAcknowledgedForScheduling).toBe("Yes"); + expect(wrapper.vm.forwardButtonAction).toHaveBeenCalled(); + wrapper.unmount(); + }); + }); + describe("in-shop Maps link", () => { const address = { city: "Lewis Center", diff --git a/src/layouts/scheduling/scheduling.vue b/src/layouts/scheduling/scheduling.vue index a3be13b82..ce27ed3b2 100644 --- a/src/layouts/scheduling/scheduling.vue +++ b/src/layouts/scheduling/scheduling.vue @@ -84,6 +84,12 @@ + @@ -98,15 +104,21 @@ import inshopSchedulingCard from "@/layouts/scheduling/inshop-scheduling-card/in import interceptOverlay from "@/ux-components/intercept-overlay/intercept-overlay"; import waitlistQuestion from "@/layouts/scheduling/waitlist-question/waitlist-question"; import schedulingZipSearch from "@/layouts/scheduling/scheduling-zip-search/scheduling-zip-search"; +import recalAckModal from "@/layouts/schedule/recal-ack-modal/recal-ack-modal.vue"; import textLink from "@/ux-components/text-link/text-link"; import store from "@/store"; import { storeActions } from "@/constants/store-actions"; -import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants"; +import { + AppointmentTypeStrings, + PREMIUM_FEE_PART_TYPE, + RECAL_ACK_YES, +} from "@/constants/schedule-constants"; import { isDropOffRouteCode } from "@/layouts/schedule/helpers/schedule-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { settleAllPromises } from "@/helpers/layout-helper"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helper"; +import { partTypeStrings } from "@/constants/part-type-strings"; import { flushPagePrereqsLogs, hasServiceZipInfo, @@ -394,6 +406,8 @@ export default { zipSearchCode: store.getters.order.serviceLocation.zipCode ?? "", datePickerKey: 0, billToAccountNumber: store.getters.order.payment?.billToAccountNumber ?? null, + isRecalAcknowledgedForScheduling: + store.getters.order.isRecalAcknowledgedForScheduling ?? "", }; }, methods: { @@ -503,6 +517,15 @@ export default { this.$refs.schedulingZipSearch?.focusZipInput(); }, async onZipSearched({ zipCode, billToAccountNumber }) { + // When recal ack applies, changing zip must re-run parts selection via service-zip. + if (this.shouldShowRecalAckModal()) { + this.$router.navigateWithSaving( + this.navigationScenarios.ZIP_CODE_CHANGED_RECAL_ACK, + this.pageName + ); + return; + } + this.billToAccountNumber = billToAccountNumber; this.isLoadingDates = true; try { @@ -731,9 +754,20 @@ export default { ); }, async forwardButtonAction() { + if (this.shouldShowRecalAckModal()) { + this.$refs.navbar.removeLoader(); + this.$refs.recalAckModal.openModal(); + return; + } + const selectedScheduling = this.selectedScheduling; const selectedDate = this.selectedDate; + await store.dispatch( + storeActions.SAVE_IS_RECAL_ACKNOWLEDGED_FOR_SCHEDULING, + this.isRecalAcknowledgedForScheduling + ); + const appointmentType = this.getInShopOrDropOffApptType(selectedScheduling); const selectedProvider = this.getSelectedProvider(appointmentType, selectedScheduling); const serviceLocation = store.getters.order.serviceLocation; @@ -826,6 +860,23 @@ export default { ); } }, + shouldShowRecalAckModal() { + if (this.isRecalAcknowledgedForScheduling === RECAL_ACK_YES) { + return false; + } + + const glassParts = store.getters.order.lineItems?.glassParts ?? []; + return glassParts.some( + (part) => + part.partType === partTypeStrings.WINDSHIELD && + part.requiresRecalibration === true && + part.canSafeliteRecalibrate === false + ); + }, + onRecalAcknowledged(isAcknowledged) { + this.isRecalAcknowledgedForScheduling = isAcknowledged; + this.forwardButtonAction(); + }, }, components: { funnelHeader, @@ -838,6 +889,7 @@ export default { interceptOverlay, waitlistQuestion, schedulingZipSearch, + recalAckModal, textLink, }, };