From 76dada014f44bf67104110358d24f9d949a2c1a7 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 20 Dec 2023 10:19:13 -0500 Subject: [PATCH 01/33] Properly align hamburger menu on confirmation page --- src/layouts/confirmation/confirmation.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/layouts/confirmation/confirmation.vue b/src/layouts/confirmation/confirmation.vue index 32904b8ee..45c73f096 100644 --- a/src/layouts/confirmation/confirmation.vue +++ b/src/layouts/confirmation/confirmation.vue @@ -1,9 +1,13 @@ @@ -89,6 +96,7 @@ export default { internalModel: deepClone(this.modelValue), displayInvalidZipAlert: false, isModalOpened: false, + displayMismatchStateAndZipAlert: false, }; }, setup(props) { @@ -213,17 +221,22 @@ export default { this.modal.closeModal(); }, onModalClosed() { - this.displayInvalidZipAlert = false; + this.resetAlerts(); this.internalModel = deepClone(this.modelValue); }, resetModalButtonStyle() { this.modal.resetButtonStyle(); }, + resetAlerts() { + this.displayInvalidZipAlert = false; + this.displayMismatchStateAndZipAlert = false; + }, async setMobileLocation() { if ( this.internalModel.addressQuestions.zipCode !== this.modelValue.addressQuestions.zipCode ) { + this.resetAlerts(); // Validate the Zip Code const zipCodeData = await this.getZipCodeData( this.internalModel.addressQuestions.zipCode, @@ -233,6 +246,9 @@ export default { if (!zipCodeData.isValid) { this.displayInvalidZipAlert = true; this.resetModalButtonStyle(); + } else if (zipCodeData.state != this.internalModel.addressQuestions.state) { + this.displayMismatchStateAndZipAlert = true; + this.resetModalButtonStyle(); } else { // retrieve mobile fee part const serviceZipCode = this.internalModel.addressQuestions.zipCode; From 19aa7d006ff63e399e84a8d28858a9a9f08333fc Mon Sep 17 00:00:00 2001 From: hiteshkumar87 Date: Fri, 22 Dec 2023 18:15:41 +0530 Subject: [PATCH 04/33] CSR-1655 Multiple tabs can merge session data --- src/store/index.js | 8 +- .../strategies/broadcastChannel.js | 31 ++++++ .../strategies/broadcastChannel.spec.js | 82 ++++++++++++++ .../strategies/defaultStrategy.js | 17 +++ .../strategies/localStorage.js | 101 ++++++++++++++++++ .../strategies/localStorage.spec.js | 22 ++++ .../vuexSharedMutations.js | 51 +++++++++ .../vuexSharedMutations.spec.js | 88 +++++++++++++++ 8 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 src/store/vuex-shared-mutations/strategies/broadcastChannel.js create mode 100644 src/store/vuex-shared-mutations/strategies/broadcastChannel.spec.js create mode 100644 src/store/vuex-shared-mutations/strategies/defaultStrategy.js create mode 100644 src/store/vuex-shared-mutations/strategies/localStorage.js create mode 100644 src/store/vuex-shared-mutations/strategies/localStorage.spec.js create mode 100644 src/store/vuex-shared-mutations/vuexSharedMutations.js create mode 100644 src/store/vuex-shared-mutations/vuexSharedMutations.spec.js diff --git a/src/store/index.js b/src/store/index.js index 918718fac..f4500fbde 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -28,6 +28,7 @@ import { removeCurrentlyActivePromoCodesFromInactivePromos, } from "@/helpers/promotions-helper"; import { getDateDifferenceInDays } from "@/helpers/date-helper"; +import sharedMutations from "./vuex-shared-mutations/vuexSharedMutations"; // Export State const getDefaultState = () => { return { @@ -2523,7 +2524,12 @@ export const actions = { }; export default createStore({ - plugins: [createPersistedState()], + plugins: [ + createPersistedState(), + sharedMutations({ + predicate: [...Object.values(storeMutations)], + }), + ], // IMPORTANT: Be VERY careful when modifying these fields for at least a few reasons: // * The CMS can reference the fields by name // * Return users may have a previous "version" of the model, and we don't want diff --git a/src/store/vuex-shared-mutations/strategies/broadcastChannel.js b/src/store/vuex-shared-mutations/strategies/broadcastChannel.js new file mode 100644 index 000000000..4bbfbad0e --- /dev/null +++ b/src/store/vuex-shared-mutations/strategies/broadcastChannel.js @@ -0,0 +1,31 @@ +const DEFAULT_CHANNEL = "vuex-shared-mutations"; + +const globalObj = + typeof window !== "undefined" ? window : /* istanbul ignore next: node env */ global; + +export default class BroadcastChannelStrategy { + static available(BroadcastChannelImpl = globalObj.BroadcastChannel) { + return !(typeof BroadcastChannelImpl !== "function"); + } + + constructor(options = {}) { + const BroadcastChannelImpl = options.BroadcastChannel || globalObj.BroadcastChannel; + const key = options.key || DEFAULT_CHANNEL; + + if (!this.constructor.available(BroadcastChannelImpl)) { + throw new Error("Broadcast strategy not available"); + } + + this.channel = new BroadcastChannelImpl(key); + } + + addEventListener(fn) { + this.channel.addEventListener("message", (e) => { + fn(e.data); + }); + } + + share(message) { + return this.channel.postMessage(message); + } +} diff --git a/src/store/vuex-shared-mutations/strategies/broadcastChannel.spec.js b/src/store/vuex-shared-mutations/strategies/broadcastChannel.spec.js new file mode 100644 index 000000000..7b5856875 --- /dev/null +++ b/src/store/vuex-shared-mutations/strategies/broadcastChannel.spec.js @@ -0,0 +1,82 @@ +import BroadcastChannelStrategy from "./broadcastChannel"; + +describe("BroadcastChannelStrategy", () => { + const mockChannel = { + addEventListener: jest.fn(), + postMessage: jest.fn(), + }; + const mockBroadcastChannel = jest.fn(() => mockChannel); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe("available", () => { + it("should return true if BroadcastChannelImpl is a function", () => { + expect(BroadcastChannelStrategy.available(mockBroadcastChannel)).toBe(true); + }); + + it("should return false if BroadcastChannelImpl is not a function", () => { + expect(BroadcastChannelStrategy.available(null)).toBe(false); + }); + }); + + describe("constructor", () => { + it("should create a new BroadcastChannel with the default channel name if no key is provided", () => { + const strategy = new BroadcastChannelStrategy({ + BroadcastChannel: mockBroadcastChannel, + }); + + expect(mockBroadcastChannel).toHaveBeenCalledWith("vuex-shared-mutations"); + expect(strategy.channel).toBe(mockChannel); + }); + + it("should create a new BroadcastChannel with the provided key", () => { + const strategy = new BroadcastChannelStrategy({ + BroadcastChannel: mockBroadcastChannel, + key: "test-channel", + }); + + expect(mockBroadcastChannel).toHaveBeenCalledWith("test-channel"); + expect(strategy.channel).toBe(mockChannel); + }); + + it("should throw an error if Broadcast strategy is not available", () => { + expect(() => new BroadcastChannelStrategy({ BroadcastChannel: null })).toThrow( + "Broadcast strategy not available" + ); + }); + }); + + describe("addEventListener", () => { + it("should add a message event listener to the channel", () => { + const strategy = new BroadcastChannelStrategy({ + BroadcastChannel: mockBroadcastChannel, + }); + const mockFn = jest.fn(); + + strategy.addEventListener(mockFn); + expect(mockChannel.addEventListener).toHaveBeenCalledWith( + "message", + expect.any(Function) + ); + + // const mockEvent = { data: "test-message" }; + // console.log(mockChannel.addEventListener.mock.calls); + // mockChannel.addEventListener.mock.calls[0][1]; + // expect(mockFn).toHaveBeenCalledWith(mockEvent.data); + }); + }); + + describe("share", () => { + it("should post a message to the channel", () => { + const strategy = new BroadcastChannelStrategy({ + BroadcastChannel: mockBroadcastChannel, + }); + const mockMessage = { test: "message" }; + + expect(strategy.share(mockMessage)).toBeUndefined(); + expect(mockChannel.postMessage).toHaveBeenCalledWith(mockMessage); + }); + }); +}); diff --git a/src/store/vuex-shared-mutations/strategies/defaultStrategy.js b/src/store/vuex-shared-mutations/strategies/defaultStrategy.js new file mode 100644 index 000000000..d1b34a8a3 --- /dev/null +++ b/src/store/vuex-shared-mutations/strategies/defaultStrategy.js @@ -0,0 +1,17 @@ +import BroadcastChannelStrategy from "./broadcastChannel"; +import LocalStorageStrategy from "./localStorage"; + +export default function createDefaultStrategy() { + /* istanbul ignore next: browser-dependent code */ + if (LocalStorageStrategy.available()) { + return new LocalStorageStrategy(); + } + + /* istanbul ignore next: browser-dependent code */ + if (BroadcastChannelStrategy.available()) { + return new BroadcastChannelStrategy(); + } + + /* istanbul ignore next: browser-dependent code */ + throw new Error("No strategies available"); +} diff --git a/src/store/vuex-shared-mutations/strategies/localStorage.js b/src/store/vuex-shared-mutations/strategies/localStorage.js new file mode 100644 index 000000000..ff3df0537 --- /dev/null +++ b/src/store/vuex-shared-mutations/strategies/localStorage.js @@ -0,0 +1,101 @@ +const DEFAULT_KEY = "vuex-shared-mutations"; + +const globalObj = + typeof window !== "undefined" ? window : /* istanbul ignore next: node env */ global; + +const MAX_MESSAGE_LENGTH = 4 * 1024; +let messageCounter = 1; + +function splitMessage(message) { + const partsCount = Math.ceil(message.length / MAX_MESSAGE_LENGTH); + return Array.from({ length: partsCount }).map((_, idx) => + message.substr(idx * MAX_MESSAGE_LENGTH, MAX_MESSAGE_LENGTH) + ); +} + +export default class LocalStorageStrategy { + static available( + { window: windowImpl, localStorage: localStorageImpl } = { + window: globalObj.window, + localStorage: globalObj.localStorage, + } + ) { + if (!windowImpl || !localStorageImpl) { + return false; + } + + try { + localStorageImpl.setItem("vuex-shared-mutations-test-key", Date.now()); + localStorageImpl.removeItem("vuex-shared-mutations-test-key"); + return true; + } catch (e) { + return false; + } + } + + constructor(options = {}) { + const windowImpl = options.window || globalObj.window; + const localStorageImpl = options.localStorage || globalObj.localStorage; + if ( + !this.constructor.available({ + window: windowImpl, + localStorage: localStorageImpl, + }) + ) { + throw new Error("Strategy unavailable"); + } + this.uniqueId = `${Date.now()}-${Math.random()}`; + this.messageBuffer = []; + this.window = windowImpl; + this.storage = localStorageImpl; + this.options = { + key: DEFAULT_KEY, + ...options, + }; + } + + // eslint-disable-next-line class-methods-use-this + addEventListener(fn) { + return this.window.addEventListener("storage", (event) => { + if (!event.newValue) { + return false; + } + + if (event.key.indexOf("##") === -1 || event.key.split("##")[0] !== this.options.key) { + return false; + } + const message = this.window.JSON.parse(event.newValue); + /* istanbul ignore next: IE does not follow storage event spec */ + if (message.author === this.uniqueId) { + return false; + } + this.messageBuffer.push(message.messagePart); + if (this.messageBuffer.length === message.total) { + const mutation = this.window.JSON.parse(this.messageBuffer.join("")); + this.messageBuffer = []; + fn(mutation); + } + return true; + }); + } + + share(message) { + const rawMessage = this.window.JSON.stringify(message); + const messageParts = splitMessage(rawMessage); + messageParts.forEach((m, idx) => { + messageCounter += 1; + const key = `${this.options.key}##${idx}`; + this.storage.setItem( + key, + JSON.stringify({ + author: this.uniqueId, + part: idx, + total: messageParts.length, + messagePart: m, + messageCounter, + }) + ); + this.storage.removeItem(key); + }); + } +} diff --git a/src/store/vuex-shared-mutations/strategies/localStorage.spec.js b/src/store/vuex-shared-mutations/strategies/localStorage.spec.js new file mode 100644 index 000000000..0dd8ee8f6 --- /dev/null +++ b/src/store/vuex-shared-mutations/strategies/localStorage.spec.js @@ -0,0 +1,22 @@ +import LocalStorageStrategy from "./localStorage"; + +describe("LocalStorageStrategy", () => { + describe("available", () => { + it("should return true if localStorage is available", () => { + const localStorageMock = { + setItem: jest.fn(), + removeItem: jest.fn(), + }; + expect( + LocalStorageStrategy.available({ window: {}, localStorage: localStorageMock }) + ).toBe(true); + }); + it("should return false if localStorage is not available", () => { + const windowMock = {}; + expect(LocalStorageStrategy.available({ window: windowMock })).toBe(false); + }); + it("should return false if window is not available", () => { + expect(LocalStorageStrategy.available({ window: undefined })).toBe(false); + }); + }); +}); diff --git a/src/store/vuex-shared-mutations/vuexSharedMutations.js b/src/store/vuex-shared-mutations/vuexSharedMutations.js new file mode 100644 index 000000000..2ccd5a53a --- /dev/null +++ b/src/store/vuex-shared-mutations/vuexSharedMutations.js @@ -0,0 +1,51 @@ +//Share vuex mutations between tabs/windows +//Referenced by https://github.com/xanf/vuex-shared-mutations/ + +import createDefaultStrategy from "./strategies/defaultStrategy"; + +export { default as BroadcastChannelStrategy } from "./strategies/broadcastChannel"; +export { default as LocalStorageStratery } from "./strategies/localStorage"; + +export default ({ predicate, strategy, ...rest } = {}) => { + /* istanbul ignore next: deprecation warning */ + if ("storageKey" in rest || "sharingKey" in rest) { + window.console.warn( + "Configuration directly on plugin was removed, configure specific strategies if needed" + ); + } + + if (!Array.isArray(predicate) && typeof predicate !== "function") { + throw new Error( + "Either array of accepted mutations or predicate function must be supplied" + ); + } + + const predicateFn = + typeof predicate === "function" ? predicate : ({ type }) => predicate.indexOf(type) !== -1; + + let sharingInProgress = false; + const selectedStrategy = strategy || createDefaultStrategy(); + return (store) => { + store.subscribe(async (mutation, state) => { + if (sharingInProgress) { + return Promise.resolve(false); + } + + const shouldShare = await Promise.resolve(predicateFn(mutation, state)); + if (!shouldShare) { + return; + } + selectedStrategy.share(mutation); + }); + + selectedStrategy.addEventListener((mutation) => { + try { + sharingInProgress = true; + store.commit(mutation.type, mutation.payload); + } finally { + sharingInProgress = false; + } + return "done"; + }); + }; +}; diff --git a/src/store/vuex-shared-mutations/vuexSharedMutations.spec.js b/src/store/vuex-shared-mutations/vuexSharedMutations.spec.js new file mode 100644 index 000000000..316e2ca29 --- /dev/null +++ b/src/store/vuex-shared-mutations/vuexSharedMutations.spec.js @@ -0,0 +1,88 @@ +import createMutationsSharer from "./vuexSharedMutations"; + +describe("Vuex shared mutations", () => { + it("should throw an error if predicate function is not supplied", () => { + expect(() => { + createMutationsSharer(); + }).toThrowError(Error); + }); + it("should accept array as predicate", () => { + expect(() => { + createMutationsSharer({ + predicate: ["m-1"], + }); + }).not.toThrowError(Error); + }); + it("should accept function as predicate", () => { + expect(() => { + createMutationsSharer({ + predicate: jest.fn(), + }); + }).not.toThrowError(Error); + }); + it("should share relevant mutation", () => { + let capturedHandler; + const fakeStrategy = { + share: jest.fn(), + addEventListener: jest.fn(), + }; + + const fakeStore = { + subscribe(fn) { + capturedHandler = fn; + }, + }; + + createMutationsSharer({ + predicate: ["m-1"], + strategy: fakeStrategy, + })(fakeStore); + + return capturedHandler({ type: "m-1", payload: "lol" }).then(() => { + expect(fakeStrategy.share).toHaveBeenCalled(); + }); + }); + it("should not share irrelevant mutation", () => { + let capturedHandler; + const fakeStrategy = { + share: jest.fn(), + addEventListener: jest.fn(), + }; + + const fakeStore = { + subscribe(fn) { + capturedHandler = fn; + }, + }; + + createMutationsSharer({ + predicate: ["m-1"], + strategy: fakeStrategy, + })(fakeStore); + return capturedHandler({ type: "m-2", payload: "lol" }).then(() => { + expect(fakeStrategy.share).not.toHaveBeenCalled(); + }); + }); + it("should respect predicate function when sharing mutation", () => { + let capturedHandler; + const fakeStrategy = { + share: jest.fn(), + addEventListener: jest.fn(), + }; + + const fakeStore = { + subscribe(fn) { + capturedHandler = fn; + }, + }; + + createMutationsSharer({ + predicate: ({ type }) => ["m-1"].indexOf(type) !== -1, + strategy: fakeStrategy, + })(fakeStore); + + return capturedHandler({ type: "m-1", payload: "lol" }).then(() => { + expect(fakeStrategy.share).toHaveBeenCalled(); + }); + }); +}); From a9d981f2003e41455034bab225326f98336b54cd Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 26 Dec 2023 16:03:16 -0500 Subject: [PATCH 05/33] Remove review page from flow --- src/router/router-constants/fmgPage-values.js | 1 - .../router-constants/navigation-scenarios.js | 8 ---- src/router/router-constants/routing-table.js | 39 +------------------ 3 files changed, 1 insertion(+), 47 deletions(-) diff --git a/src/router/router-constants/fmgPage-values.js b/src/router/router-constants/fmgPage-values.js index 7b840ce18..3bd994ad3 100644 --- a/src/router/router-constants/fmgPage-values.js +++ b/src/router/router-constants/fmgPage-values.js @@ -15,7 +15,6 @@ const fmgPageValues = { HERITAGE: "heritage", SCHEDULE: "schedule", CUSTOMER_DETAILS: "customer-details", - REVIEW: "review", PAYMENT_METHOD: "payment-method", PAYMENT: "payment", PAYMENT_PIA_RETURN: "payment-pia-return", diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 01f8e503f..13906f755 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -44,14 +44,6 @@ const navigationScenarios = { // Schedule CLICKED_CHANGE_LOCATION: "CLICKED_CHANGE_LOCATION", - // Review - CLICKED_VEHICLE_EDIT: "CLICKED_VEHICLE_EDIT", - CLICKED_DAMAGE_EDIT: "CLICKED_DAMAGE_EDIT", - CLICKED_SERVICE_PACKAGE_EDIT: "CLICKED_SERVICE_PACKAGE_EDIT", - CLICKED_SERVICE_LOCATION_EDIT: "CLICKED_SERVICE_LOCATION_EDIT", - CLICKED_SCHEDULE_EDIT: "CLICKED_SCHEDULE_EDIT", - CLICKED_CUSTOMER_EDIT: "CLICKED_CUSTOMER_EDIT", - // Payment CLICKED_PAY_NOW: "CLICKED_PAY_NOW", PIA_ERROR: "PIA_ERROR", diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 841d57fd8..052bda142 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -428,43 +428,6 @@ const routingTable = function (store) { scenario: navigationScenarios.CLICKED_BACK, destinationFmgPageValue: fmgPageValues.SCHEDULE, }, - { - scenario: navigationScenarios.CLICKED_FORWARD, - destinationFmgPageValue: fmgPageValues.REVIEW, - }, - ], - }, - { - fmgPageValue: fmgPageValues.REVIEW, - maps: [ - { - scenario: navigationScenarios.CLICKED_VEHICLE_EDIT, - destinationFmgPageValue: fmgPageValues.VEHICLE, - }, - { - scenario: navigationScenarios.CLICKED_DAMAGE_EDIT, - destinationFmgPageValue: fmgPageValues.VEHICLE_DAMAGE, - }, - { - scenario: navigationScenarios.CLICKED_SERVICE_PACKAGE_EDIT, - destinationFmgPageValue: fmgPageValues.QUOTE, - }, - { - scenario: navigationScenarios.CLICKED_BACK, - destinationFmgPageValue: fmgPageValues.CUSTOMER_DETAILS, - }, - { - scenario: navigationScenarios.CLICKED_SERVICE_LOCATION_EDIT, - destinationFmgPageValue: fmgPageValues.SERVICE_LOCATION, - }, - { - scenario: navigationScenarios.CLICKED_SCHEDULE_EDIT, - destinationFmgPageValue: fmgPageValues.SCHEDULE, - }, - { - scenario: navigationScenarios.CLICKED_CUSTOMER_EDIT, - destinationFmgPageValue: fmgPageValues.CUSTOMER_DETAILS, - }, { scenario: navigationScenarios.CLICKED_FORWARD, destinationFmgPageValue: fmgPageValues.PAYMENT_METHOD, @@ -476,7 +439,7 @@ const routingTable = function (store) { maps: [ { scenario: navigationScenarios.CLICKED_BACK, - destinationFmgPageValue: fmgPageValues.REVIEW, + destinationFmgPageValue: fmgPageValues.CUSTOMER_DETAILS, }, { scenario: navigationScenarios.CLICKED_FORWARD, From d9e0b0bc1ae559c4d56017d0629c954631ce6872 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 26 Dec 2023 16:44:02 -0500 Subject: [PATCH 06/33] Big shuffle pt. 1 --- src/layouts/payment-method/payment-method.vue | 6 ++++ .../review-block/review-block.spec.js | 2 +- .../review-block/review-block.vue | 17 ----------- .../review-dropdown/review-dropdown.vue | 28 +++++++++++++++++++ .../customer-review/customer-review.spec.js | 2 +- .../customer-review/customer-review.vue | 8 ++---- .../damage-review/damage-review.spec.js | 2 +- .../damage-review/damage-review.vue | 3 +- .../schedule-review/schedule-review.vue | 3 +- .../service-location-review.spec.js | 2 +- .../service-location-review.vue | 3 +- .../service-package-review.spec.js | 2 +- .../service-package-review.vue | 3 +- .../vehicle-review/vehicle-review.spec.js | 2 +- .../vehicle-review/vehicle-review.vue | 3 +- .../{review.spec.js => review.spec.norun.js} | 0 .../review/{review.vue => reviewn.vuenorun} | 0 17 files changed, 47 insertions(+), 39 deletions(-) rename src/layouts/{review => payment-method/review-dropdown}/review-block/review-block.spec.js (91%) rename src/layouts/{review => payment-method/review-dropdown}/review-block/review-block.vue (64%) create mode 100644 src/layouts/payment-method/review-dropdown/review-dropdown.vue rename src/layouts/{review => payment-method/review-dropdown}/review-sections/customer-review/customer-review.spec.js (96%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/customer-review/customer-review.vue (78%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/damage-review/damage-review.spec.js (99%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/damage-review/damage-review.vue (97%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/schedule-review/schedule-review.vue (85%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/service-location-review/service-location-review.spec.js (96%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/service-location-review/service-location-review.vue (92%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/service-package-review/service-package-review.spec.js (99%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/service-package-review/service-package-review.vue (96%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/vehicle-review/vehicle-review.spec.js (90%) rename src/layouts/{review => payment-method/review-dropdown}/review-sections/vehicle-review/vehicle-review.vue (82%) rename src/layouts/review/{review.spec.js => review.spec.norun.js} (100%) rename src/layouts/review/{review.vue => reviewn.vuenorun} (100%) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 5311c2728..354700279 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -21,6 +21,10 @@
+ + +
+ diff --git a/src/layouts/review/review-block/review-block.spec.js b/src/layouts/payment-method/review-dropdown/review-block/review-block.spec.js similarity index 91% rename from src/layouts/review/review-block/review-block.spec.js rename to src/layouts/payment-method/review-dropdown/review-block/review-block.spec.js index 1a25e8bfd..bf0557d05 100644 --- a/src/layouts/review/review-block/review-block.spec.js +++ b/src/layouts/payment-method/review-dropdown/review-block/review-block.spec.js @@ -1,7 +1,7 @@ import { shallowMount } from "@vue/test-utils"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; import store from "@/store"; -import reviewBlock from "@/layouts/review/review-block/review-block"; +import reviewBlock from "@/layouts/payment-method/review-dropdown/review-block/review-block"; jest.mock("@/helpers/cms-content-helper", () => ({ fetchCmsContentForPage: () => Promise.resolve("content"), diff --git a/src/layouts/review/review-block/review-block.vue b/src/layouts/payment-method/review-dropdown/review-block/review-block.vue similarity index 64% rename from src/layouts/review/review-block/review-block.vue rename to src/layouts/payment-method/review-dropdown/review-block/review-block.vue index f5819ca8c..5bf49809f 100644 --- a/src/layouts/review/review-block/review-block.vue +++ b/src/layouts/payment-method/review-dropdown/review-block/review-block.vue @@ -6,17 +6,6 @@ :customText="customHeaderText" typeStyle="body small bold dark" marginTopSizeOverride="0" /> - - -
+

review component added

+ + + diff --git a/src/layouts/review/review-sections/customer-review/customer-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js similarity index 96% rename from src/layouts/review/review-sections/customer-review/customer-review.spec.js rename to src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js index 45627df2e..13138a182 100644 --- a/src/layouts/review/review-sections/customer-review/customer-review.spec.js +++ b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js @@ -1,7 +1,7 @@ import { shallowMount } from "@vue/test-utils"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import customerReview from "@/layouts/review/review-sections/customer-review/customer-review"; +import customerReview from "@/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review"; const testConstants = { cms: { diff --git a/src/layouts/review/review-sections/customer-review/customer-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.vue similarity index 78% rename from src/layouts/review/review-sections/customer-review/customer-review.vue rename to src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.vue index f3f664927..2fd82c716 100644 --- a/src/layouts/review/review-sections/customer-review/customer-review.vue +++ b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.vue @@ -1,13 +1,9 @@ + + From b9e11e7fd2e017ed93fb439cf46db864ee3d13a2 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Wed, 27 Dec 2023 12:33:19 -0500 Subject: [PATCH 10/33] Big shuffle pt.2 --- src/layouts/review/review.spec.norun.js | 362 ------------------------ src/layouts/review/reviewn.vuenorun | 330 --------------------- 2 files changed, 692 deletions(-) delete mode 100644 src/layouts/review/review.spec.norun.js delete mode 100644 src/layouts/review/reviewn.vuenorun diff --git a/src/layouts/review/review.spec.norun.js b/src/layouts/review/review.spec.norun.js deleted file mode 100644 index a4f82451d..000000000 --- a/src/layouts/review/review.spec.norun.js +++ /dev/null @@ -1,362 +0,0 @@ -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import store from "@/store"; - -import review from "@/layouts/review/review"; - -const testConstants = {}; - -jest.mock("@/store", () => ({ - commit: jest.fn(), - dispatch: jest.fn(), -})); - -describe("Review Page", () => { - beforeEach(() => { - store.getters = { - order: { - vehicle: { - year: "2020", - make: "Acura", - model: "MDX", - style: "4 door sedan", - }, - damage: { - isRepair: false, - numberOfChips: 2, - glassToReplace: ["dummy location value"], - }, - lineItems: { - glassParts: ["dummy part value"], - supportingItems: ["dummy supporting item"], - vaps: ["dummy vap"], - }, - serviceLocation: { - address: "address 1", - address2: "address 2", - city: "city", - state: "state", - zipCode: "zip code", - appointmentType: "Mobile", - provider: { - providerNumber: 1, - address: { - streetAddress: "provider address 1", - city: "provider city", - state: "provider state", - zipCode: "provider zip code", - }, - }, - }, - schedule: { - date: "date", - startTime: "start", - endTime: "end", - jobMinMinutes: "30", - jobMaxMinutes: "45", - }, - customer: { - firstName: "first name", - lastName: "last name", - emailAddress: "builddigitaltest@safelite.com", - phoneNumber: "555-555-5555", - isSmsOptIn: true, - }, - }, - }; - }); - describe("arePagePrerequisitesValid", () => { - test("Returns true for baseline valid state", () => { - // Arrange - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test("Returns false for empty state", () => { - // Arrange - store.getters.order = { - vehicle: { - year: null, - make: null, - model: null, - style: null, - carId: null, - category: null, - vin: null, - imageUrl: null, - imageVifNumber: null, - imageColor: null, - registration: { - licensePlate: null, - }, - }, - serviceLocation: { - address: null, - address2: null, - city: null, - state: null, - zipCode: null, - zipCodeCtu: null, - appointmentType: null, - isVehicleProtected: null, - provider: { - providerNumber: null, - address: { - streetAddress: null, - city: null, - state: null, - zipCode: null, - zipCodeCtu: null, - }, - }, - techNotes: null, - }, - customer: { - firstName: null, - lastName: null, - emailAddress: null, - phoneNumber: null, - isSmsOptIn: null, - }, - damage: { - isRepair: null, - numberOfChips: null, - glassToReplace: null, - partQuestionAnswers: null, - moldingQuestionAnswers: null, - capabilityQuestionAnswers: null, - }, - lineItems: { - glassParts: null, - supportingItems: null, - vaps: null, - serverData: null, - }, - payment: { - isInsurance: null, - insuranceCoverage: { - isVerified: null, - coverageStatus: null, - }, - parentAccountNumber: 0, - }, - schedule: { - date: null, - startTime: null, - endTime: null, - routeCode: null, - jobMaxMinutes: null, - jobMinMinutes: null, - }, - referralNumber: null, - referralSequenceNumber: null, - referralDate: null, - referralCorrelationId: null, - eon: null, - }; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - describe("Damage requirements", () => { - test("Accepts null glassToReplace when is repair", () => { - // Arrange - store.getters.order.damage.isRepair = true; - store.getters.order.damage.glassToReplace = null; - store.getters.order.damage.numberOfChips = 1; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test("Rejects 0 chips when repair", () => { - // Arrange - store.getters.order.damage.isRepair = true; - store.getters.order.damage.numberOfChips = 0; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - test("Rejects null chips when repair", () => { - // Arrange - store.getters.order.damage.isRepair = true; - store.getters.order.damage.numberOfChips = null; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - test("Accepts null chips when not repair", () => { - // Arrange - store.getters.order.damage.isRepair = false; - store.getters.order.damage.numberOfChips = null; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test("Rejects empty glassToReplace when not repair", () => { - // Arrange - store.getters.order.damage.isRepair = false; - store.getters.order.damage.glassToReplace = null; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - test("Rejects null glassToReplace when not repair", () => { - // Arrange - store.getters.order.damage.isRepair = false; - store.getters.order.damage.glassToReplace = []; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - }); - describe("Package requirements", () => { - test("Accepts null glassParts when is repair", () => { - // Arrange - store.getters.order.damage.isRepair = true; - store.getters.order.lineItems.glassParts = null; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test("Rejects null glassParts when not repair", () => { - // Arrange - store.getters.order.damage.isRepair = false; - store.getters.order.lineItems.glassParts = null; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - }); - describe("Service Location requirements", () => { - test("Accepts null provider address when mobile appointment", () => { - // Arrange - store.getters.order.serviceLocation.appointmentType = "Mobile"; - store.getters.order.serviceLocation.provider.address = {}; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test("Reject null provider address when non-mobile appointment", () => { - // Arrange - store.getters.order.serviceLocation.appointmentType = "Inshop"; - store.getters.order.serviceLocation.provider.address = {}; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - test("Accepts null service location address when non-mobile appointment", () => { - // Arrange - store.getters.order.serviceLocation.appointmentType = "Inshop"; - store.getters.order.serviceLocation.address = null; - store.getters.order.serviceLocation.address2 = null; - store.getters.order.serviceLocation.zipCode = null; - store.getters.order.serviceLocation.city = null; - store.getters.order.serviceLocation.state = null; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test("Rejects null service location address when mobile appointment", () => { - // Arrange - store.getters.order.serviceLocation.appointmentType = "Mobile"; - store.getters.order.serviceLocation.address = null; - store.getters.order.serviceLocation.address2 = null; - store.getters.order.serviceLocation.zipCode = null; - store.getters.order.serviceLocation.city = null; - store.getters.order.serviceLocation.state = null; - - const { wrapper } = setupMocks({}); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - }); - }); -}); - -function setupMocks(customMountOptions) { - customMountOptions.store = store; - - const mountOptions = getMountOptions(customMountOptions); - - const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return `${widgetName} ${cmsFieldName}`; - }), - }, - }; - - mountOptions.global.mixins = [mockMixin]; - - const wrapper = shallowMount(review, mountOptions); - wrapper.vm.setCmsContent = jest.fn(); - return { wrapper }; -} diff --git a/src/layouts/review/reviewn.vuenorun b/src/layouts/review/reviewn.vuenorun deleted file mode 100644 index d6ad0aa82..000000000 --- a/src/layouts/review/reviewn.vuenorun +++ /dev/null @@ -1,330 +0,0 @@ - - - - - From 088800d45f0ca229682a9dbd98c070fdce5e9375 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Thu, 28 Dec 2023 09:37:08 -0500 Subject: [PATCH 11/33] Expand toggle --- .../review-block/review-block.vue | 1 - .../review-dropdown/review-dropdown.vue | 75 ++++++++++++++++--- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/layouts/payment-method/review-dropdown/review-block/review-block.vue b/src/layouts/payment-method/review-dropdown/review-block/review-block.vue index cdf751507..6afd393d5 100644 --- a/src/layouts/payment-method/review-dropdown/review-block/review-block.vue +++ b/src/layouts/payment-method/review-dropdown/review-block/review-block.vue @@ -34,7 +34,6 @@ export default { methods: {}, components: { textBlock, - textLink, }, }; diff --git a/src/layouts/payment-method/review-dropdown/review-dropdown.vue b/src/layouts/payment-method/review-dropdown/review-dropdown.vue index f63af4a8b..321599820 100644 --- a/src/layouts/payment-method/review-dropdown/review-dropdown.vue +++ b/src/layouts/payment-method/review-dropdown/review-dropdown.vue @@ -1,13 +1,17 @@