diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 5ff1f636c..a0009bae0 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -2,6 +2,7 @@ const queryStrings = { FMG_PAGE: "fmgPage", START_TYPE: "start_type", ZIP_CODE: "zipcode", + PROMO: "promo", }; export { queryStrings }; diff --git a/src/helpers/date-helper.js b/src/helpers/date-helper.js new file mode 100644 index 000000000..dce497231 --- /dev/null +++ b/src/helpers/date-helper.js @@ -0,0 +1,10 @@ +export function getDateDifferenceInDays(startDate, endDate) { + var date1 = new Date(endDate); + date1.setHours(0, 0, 0, 0); + var date2 = new Date(startDate); + date2.setHours(0, 0, 0, 0); + // To calculate the time difference of two dates + var Difference_In_Time = date1.getTime() - date2.getTime(); + // To calculate the no. of days between two dates + return Difference_In_Time / (1000 * 3600 * 24); +} diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index fe6a16591..5b421b056 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -1,4 +1,5 @@ import { queryStrings } from "@/constants/query-strings"; +import { getQuerystringParameter } from "@/helpers/querystring-helper"; import { externalUrls } from "@/router/router-constants/externalUrl-values"; import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js"; import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; @@ -16,15 +17,11 @@ import router from "@/router"; drop them so they don't start at the beginning again. This method will return 'heritage' if the user has an existing order and they come back in from the Safelite.com CTA. */ -export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHeritageOrder = false) { +export async function getPageToRouteExistingOrderTo(toRoute = {}) { // If the user is coming in via the Safelite.Com CTA if (toRoute.query[queryStrings.START_TYPE] === "fmg") { - // If they have an existing order, return 'heritage' for the page name. - if (existingHeritageOrder) { - return fmgPageValues.HERITAGE; - } - - return await getLatestPageForRedirection(); + const latestPageRoute = await getLatestPageForRedirection(); + return latestPageRoute; } // If navigating to a specific page, and that page is not part of the vin pages. @@ -41,7 +38,6 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHerita // If this is not a direct link to a page using fmgPage, not from Safelite.com CTA or this is a vin related page. // Get the latest page for redirection. const latestPageRoute = await getLatestPageForRedirection(); - return latestPageRoute; } @@ -49,7 +45,7 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}, existingHerita Used to navigate to the heritage funnel with the correct query string and url. */ -export async function navigateToHeritageFunnel({ shouldSaveSession = true, loadingModal }) { +export async function navigateToHeritageFunnel({ shouldSaveSession, loadingModal }) { // Create the order (or save existing order) when navigating to Heritage Funnel. if (shouldSaveSession) { await saveSession({ shouldAwaitSaveSessionQueue: true }); @@ -59,21 +55,31 @@ export async function navigateToHeritageFunnel({ shouldSaveSession = true, loadi loadingModal.showModal(); } - router.navigateToExternalUrl(externalUrls.HERITAGE_FUNNEL, { + var heritageParms = { corid: store.getters.order.referralCorrelationId, src: "concept-funnel", conceptsqid: store.getters.applicationUser.savedSessionId, isInsurance: store.getters.payment.isInsurance, - }); + }; + + const promo = getQuerystringParameter(queryStrings.PROMO); + + if (promo) { + heritageParms["promo"] = promo; + } + + router.navigateToExternalUrl(externalUrls.HERITAGE_FUNNEL, heritageParms); } export async function skipVinLookup() { + if (store.getters.damage.isRepair) { + return true; + } const isVinOptionalVehicle = store.getters.order.vehicle.make ? await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE) : false; return ( - store.getters.damage.isRepair || isVinOptionalVehicle || !includesWindshieldReplacement() || experimentMixin.methods.hasSettingEqualTo(experimentSettings.SUPPRESS_VIN_CAPTURE, "true") @@ -81,18 +87,18 @@ export async function skipVinLookup() { } export async function skipVinLookupNotRepair() { + if (store.getters.damage.isRepair) { + return false; + } + const isVinOptionalVehicle = store.getters.order.vehicle.make ? await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE) : false; return ( - !store.getters.damage.isRepair && - (isVinOptionalVehicle || - !includesWindshieldReplacement() || - experimentMixin.methods.hasSettingEqualTo( - experimentSettings.SUPPRESS_VIN_CAPTURE, - "true" - )) + isVinOptionalVehicle || + !includesWindshieldReplacement() || + experimentMixin.methods.hasSettingEqualTo(experimentSettings.SUPPRESS_VIN_CAPTURE, "true") ); } diff --git a/src/helpers/heritage-integration/navigation-helper.spec.js b/src/helpers/heritage-integration/navigation-helper.spec.js index cb0664f78..e0bd51b95 100644 --- a/src/helpers/heritage-integration/navigation-helper.spec.js +++ b/src/helpers/heritage-integration/navigation-helper.spec.js @@ -36,7 +36,7 @@ describe("getPageToRouteExistingOrderTo", () => { }); // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); + const result = await getPageToRouteExistingOrderTo(toRoute); //Assert expect(result).toBe(fmgPageValues.VEHICLE); @@ -59,7 +59,7 @@ describe("getPageToRouteExistingOrderTo", () => { }); // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); + const result = await getPageToRouteExistingOrderTo(toRoute); //Assert expect(result).toBe(fmgPageValues.VEHICLE_DAMAGE); @@ -97,7 +97,7 @@ describe("getPageToRouteExistingOrderTo", () => { }); // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); + const result = await getPageToRouteExistingOrderTo(toRoute); //Assert expect(result).toBe(fmgPageValues.ESTIMATE); @@ -125,7 +125,7 @@ describe("getPageToRouteExistingOrderTo", () => { }); // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); + const result = await getPageToRouteExistingOrderTo(toRoute); //Assert expect(result).toBe(fmgPageValues.ESTIMATE); @@ -153,7 +153,7 @@ describe("getPageToRouteExistingOrderTo", () => { }); // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); + const result = await getPageToRouteExistingOrderTo(toRoute); //Assert expect(result).toBe(fmgPageValues.CAPABILITY_QUESTIONS); @@ -181,7 +181,7 @@ describe("getPageToRouteExistingOrderTo", () => { }); // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); + const result = await getPageToRouteExistingOrderTo(toRoute); //Assert expect(result).toBe(fmgPageValues.MOLDING_QUESTIONS); @@ -209,7 +209,7 @@ describe("getPageToRouteExistingOrderTo", () => { }); // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); + const result = await getPageToRouteExistingOrderTo(toRoute); //Assert expect(result).toBe(fmgPageValues.VEHICLE_PARTS); @@ -237,29 +237,11 @@ describe("getPageToRouteExistingOrderTo", () => { }); // Act - const result = await getPageToRouteExistingOrderTo(toRoute, false); + const result = await getPageToRouteExistingOrderTo(toRoute); //Assert expect(result).toBe(fmgPageValues.PART_QUESTIONS); }); - - test("existing order > should return heritage", async () => { - // Arrange - const toRoute = { - query: { - [queryStrings.START_TYPE]: "fmg", - }, - }; - - store.commit(storeMutations.UPDATE_IS_REPAIR, false); - store.commit(storeMutations.UPDATE_MAKE, "acura"); - - // Act - const result = await getPageToRouteExistingOrderTo(toRoute, true); - - // Assert - expect(result).toBe(fmgPageValues.HERITAGE); - }); }); describe("navigateToHeritageFunnel", () => { @@ -295,7 +277,7 @@ describe("navigateToHeritageFunnel", () => { router.navigateToExternalUrl = jest.fn(); // Act - await navigateToHeritageFunnel({}); + await navigateToHeritageFunnel({ loadingModal: null, shouldSaveSession: true }); // Assert expect(saveSessionFunction).toHaveBeenCalled(); diff --git a/src/layouts/estimate/estimate.vue b/src/layouts/estimate/estimate.vue index dff601165..23420751d 100644 --- a/src/layouts/estimate/estimate.vue +++ b/src/layouts/estimate/estimate.vue @@ -252,7 +252,10 @@ export default { const vehicleChangedDuringPolicyLookupInHeritage = payment.isInsurance && payment.insuranceCoverage.coverageStatus; if (vehicleChangedDuringPolicyLookupInHeritage) { - navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal }); + navigateToHeritageFunnel({ + shouldSaveSession: true, + loadingModal: this.$refs.loadingModal, + }); } else if (this.$store.getters.order.referralNumber?.length === 6) { await this.navigateForwardWithSingleCarMatch(); } else if (this.isRepair) { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 72d519028..3076e8acc 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -121,6 +121,12 @@ export default { false ); + baseMixin.methods.dispatchStoreAction( + storeActions.SAVE_SUPPORTING_ITEMS, + resultMap.supportingItems, + false + ); + // Call the "next" function to complete the transition to this page. next((vm) => { vm.setCmsContent(resultMap.cmsContent); @@ -213,17 +219,14 @@ export default { ); } - this.dispatchStoreAction( - this.storeActions.SAVE_SUPPORTING_ITEMS, - this.supportingItems, - false - ); - this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false); const payment = this.$store.getters.payment; if (payment.isInsurance) { - navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal }); + navigateToHeritageFunnel({ + shouldSaveSession: true, + loadingModal: this.$refs.loadingModal, + }); } else { this.$router.navigateWithSaving( this.navigationScenarios.CLICKED_FORWARD_WITH_CASH, diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 9fca2f77e..e49cd295c 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -116,6 +116,8 @@ import store from "@/store"; import { defineRule } from "vee-validate"; import { errorMessages } from "@/constants/error-messages"; +const MOBILE_FEE_PART_TYPE = "MOBILE FEE"; + // DEFINE VALIDATION RULES defineRule("mobile-location-required", (value) => { if ( @@ -375,6 +377,43 @@ export default { backButtonAction() { this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); }, + updateAndSaveSupportingItems() { + const supportingItems = store.getters.lineItems.supportingItems; + // if we have a mobile fee, then save/update supporting items + if (this.selectedAppointmentType == "Mobile") { + const mobileFeeIndex = supportingItems.findIndex( + (item) => item.partType == MOBILE_FEE_PART_TYPE + ); + // If it already exists, update the price with latest data + if (mobileFeeIndex >= 0) { + supportingItems[mobileFeeIndex].laborAmount = this.mobileFeePart.laborAmount; + supportingItems[mobileFeeIndex].selingPrice = this.mobileFeePart.selingPrice; + supportingItems[mobileFeeIndex].kitPrice = this.mobileFeePart.kitPrice; + } else { + supportingItems.push(this.mobileFeePart); + } + + this.dispatchStoreAction( + this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING, + supportingItems, + false + ); + } else { + // if it's not a mobile, then make sure we remove any that may have been added + const removeMobileFeeIndex = supportingItems.findIndex( + (item) => item.partType == MOBILE_FEE_PART_TYPE + ); + + if (removeMobileFeeIndex >= 0) { + supportingItems.splice(removeMobileFeeIndex, 1); + this.dispatchStoreAction( + this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING, + supportingItems, + false + ); + } + } + }, async forwardButtonAction() { await this.dispatchStoreAction( this.storeActions.SAVE_SERVICE_LOCATION, @@ -401,6 +440,7 @@ export default { false ); + this.updateAndSaveSupportingItems(); this.$router.navigateWithSaving(this.navigationScenarios.CLICKED_FORWARD, this.$route); }, openModalAction(modalName) { diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 4b05067ea..fb54c059f 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -447,9 +447,15 @@ export default { const payment = store.getters.payment; if (store.getters.order.referralNumber?.length === 6) { - navigateToHeritageFunnel({ loadingModal: self.$refs.loadingModal }); + navigateToHeritageFunnel({ + shouldSaveSession: true, + loadingModal: self.$refs.loadingModal, + }); } else if (payment.isInsurance && payment.insuranceCoverage.isVerified) { - navigateToHeritageFunnel({ loadingModal: self.$refs.loadingModal }); + navigateToHeritageFunnel({ + shouldSaveSession: true, + loadingModal: self.$refs.loadingModal, + }); } else { self.$router.navigateWithSaving( self.navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS, diff --git a/src/router/index.js b/src/router/index.js index e8fbf4d26..a9fba2837 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -6,6 +6,7 @@ import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js" import { routingTable } from "@/router/router-constants/routing-table.js"; import { globalEvents, globalEventTypes } from "@/constants/events"; import { queryStrings } from "@/constants/query-strings"; +import { getQuerystringParameter } from "@/helpers/querystring-helper"; import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper"; // Heritage integration @@ -74,17 +75,7 @@ const routes = [ : null ); - const pageToRedirectTo = await getPageToRouteExistingOrderTo( - to, - loadSessionResponse - ); - - // If getPageToRouteExistingOrderTo determines that the return user needs to - // go back to heritage funnel, send them there and stop our current navigation. - if (pageToRedirectTo === "heritage") { - await navigateToHeritageFunnel(); - return next(false); - } + const pageToRedirectTo = await getPageToRouteExistingOrderTo(to); // Assign our fmgPage so it will load normally like the other pages. to.query.fmgPage = pageToRedirectTo; @@ -284,14 +275,9 @@ async function navigate( fmgPage: destinationFmgPageValue, }; - const queryString = window.location.search; - const urlParams = new URLSearchParams(queryString); - const lowerCaseParams = new URLSearchParams(); - for (const [name, value] of urlParams) { - lowerCaseParams.append(name.toLowerCase(), value); - } - const hasZip = lowerCaseParams.has(queryStrings.ZIP_CODE); - const zip = lowerCaseParams.get(queryStrings.ZIP_CODE); + const hasZip = getQuerystringParameter(queryStrings.ZIP_CODE); + const zip = getQuerystringParameter(queryStrings.ZIP_CODE); + const promo = getQuerystringParameter(queryStrings.PROMO); if ( hasZip && @@ -303,6 +289,10 @@ async function navigate( queryStringsObject[queryStrings.ZIP_CODE] = zip; } + if (promo) { + queryStringsObject[queryStrings.PROMO] = promo; + } + router.push({ name: "root", query: Object.assign(optionalQuery, queryStringsObject), diff --git a/src/store/index.js b/src/store/index.js index 95a028aae..f6f773cfc 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -22,6 +22,7 @@ import { getDisplayTextForDurationLength, } from "@/layouts/schedule/helpers/schedule-helper"; +import { getDateDifferenceInDays } from "@/helpers/date-helper"; // Export State const getDefaultState = () => { return { @@ -634,8 +635,24 @@ function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) { return (array ?? []).map((x) => x[propertyName]).filter((x) => x); } -function provisionalTriggersToString(provisionalTriggers) { - return "ProvisionalTriggers:" + provisionalTriggers.join(","); +function getTimeSlotsAdditionalEventData( + provisionalTriggers, + zipCode, + firstAvailableAppointmentDateString, + shopAppointmentType +) { + var numberOfDays = null; + if (firstAvailableAppointmentDateString) + numberOfDays = getDateDifferenceInDays(new Date(), firstAvailableAppointmentDateString); + + if (shopAppointmentType) + return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ShopAppointmentType:${shopAppointmentType},ProvisionalTriggers:${provisionalTriggers.join( + "," + )}`; + else + return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ProvisionalTriggers:${provisionalTriggers.join( + "," + )}`; } // Export Actions @@ -1315,7 +1332,12 @@ export const actions = { endpoint: endpoints.GetShopTimeSlots.url, payload: payload, additionalSuccessEventDataHandler: (response) => - provisionalTriggersToString(response.data.provisionalTriggers), + getTimeSlotsAdditionalEventData( + response.data.provisionalTriggers, + order.serviceLocation.zipCode, + response.data.days?.[0]?.date, + shopAppointmentType + ), }); }, @@ -1372,7 +1394,11 @@ export const actions = { endpoint: endpoints.GetMobileTimeSlots.url, payload: payload, additionalSuccessEventDataHandler: (response) => - provisionalTriggersToString(response.data.provisionalTriggers), + getTimeSlotsAdditionalEventData( + response.data.provisionalTriggers, + order.serviceLocation.zipCode, + response.data.days?.[0]?.date + ), }); },