diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 86df61063..87331daea 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -23,7 +23,7 @@ const storeActions = { GET_PARTS: "getParts", SAVE_ORDER: "saveOrder", LOAD_ORDER: "loadOrder", - SET_REFERRAL_INFORMATION: "setReferralInformation", + UPDATE_STORE_WITH_SAVE_ORDER_RESPONSE: "updateStoreWithSaveOrderResponse", VALIDATE_ZIP: "validateZip", LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure", LOG_PAGE_VIEW: "logPageView", diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 167e0710c..80697cc46 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -39,6 +39,8 @@ const storeMutations = { UPDATE_REFERRAL_DATE: "updateReferralDate", UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId", UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber", + UPDATE_SAVE_QUOTE_ID: "updateSaveQuoteId", + UPDATE_CRM_CUSTOMER_ID: "updateCrmCustomerId", // EVENT BUS MUTATIONS ADD_EVENT_TO_BUS: "addEventToBus", @@ -54,6 +56,8 @@ const storeMutations = { // OTHER MUTATIONS UPDATE_PAGE_DATA: "updatePageData", UPDATE_STATE_WITH_ORDER_INFORMATION: "updateStateWithOrderInformation", + UPDATE_SAVE_ORDER_PROMISE: "updateSaveOrderPromise", + UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited", }; export { storeMutations }; diff --git a/src/helpers/heritage-integration/navigation-helper.spec.js b/src/helpers/heritage-integration/navigation-helper.spec.js index e212284b8..e78782d7c 100644 --- a/src/helpers/heritage-integration/navigation-helper.spec.js +++ b/src/helpers/heritage-integration/navigation-helper.spec.js @@ -308,8 +308,11 @@ describe("navigateToHeritageFunnel", () => { const mockReferralNumber = "2"; const mockCorrelationId = "55"; const mockReferralDate = "2022"; + const mockAccountNumber = "167132"; + const mockSaveQuoteId = "xxx-xxx-xxx"; + const mockCrmCustomerId = "xxx-xxx-xxx" - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate); + const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSaveQuoteId, mockCrmCustomerId); const mockData = { actionList: [{ @@ -340,8 +343,11 @@ describe("navigateToHeritageFunnel", () => { const mockReferralNumber = "2"; const mockCorrelationId = "55"; const mockReferralDate = "2022"; + const mockAccountNumber = "167132"; + const mockSaveQuoteId = "xxx-xxx-xxx"; + const mockCrmCustomerId = "xxx-xxx-xxx" - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate); + const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSaveQuoteId, mockCrmCustomerId); const mockData = { actionList: [{ diff --git a/src/helpers/heritage-integration/order-helper.js b/src/helpers/heritage-integration/order-helper.js index 962550592..9722744f0 100644 --- a/src/helpers/heritage-integration/order-helper.js +++ b/src/helpers/heritage-integration/order-helper.js @@ -1,6 +1,8 @@ import { storeActions } from "@/constants/store-actions.js"; import { getFunnelCookie, updateOrCreateFunnelCookie, deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js"; import baseMixin from "@/mixins/base-mixin"; +import store from "@/store"; +import { storeMutations } from "@/constants/store-mutations"; /* Will call API and hydrate state with data from API if present. If there is no order present @@ -34,18 +36,20 @@ export async function loadOrderIfPresent() { update the cookie. */ export async function saveOrder() { - const savedOrderInfo = await baseMixin.methods.dispatchStoreAction(storeActions.SAVE_ORDER); - - // Save the referral information back from the store. - await baseMixin.methods.dispatchStoreAction(storeActions.SET_REFERRAL_INFORMATION, { - referralNumber: savedOrderInfo.data.referralNumber.toString(), - referralCorrelationId: savedOrderInfo.data.referralCorrelationId, - referralDate: savedOrderInfo.data.referralDate, - accountNumber: savedOrderInfo.data.accountNumber.toString() - }, false); - - // Update the cookie with the referral information when saved. - updateOrCreateFunnelCookie(); + var saveOrderPromise; + if (store.getters.applicationUser.saveOrderPromise) { + // queue newest request after current saveOrderPromise resolves + saveOrderPromise = store.getters.applicationUser.saveOrderPromise.then(() => { + // get a new saveOrderPromise + return saveOrderHelper(); + }); + } else { + // create an initial saveOrderPromise + saveOrderPromise = saveOrderHelper(); + } + store.commit(storeMutations.UPDATE_SAVE_ORDER_PROMISE, saveOrderPromise); + // await here to allow for a caller to await and make the function synchronous + await saveOrderPromise; } @@ -65,4 +69,23 @@ async function loadOrder(referralNumber, referralDate, referralCorrelationId, ac }, false); return response; +} + +/* + Encapsulates asynchronous Save Order logic inside a promise to allow for Save Order queuing +*/ +async function saveOrderHelper() { + const savedOrderInfo = await baseMixin.methods.dispatchStoreAction(storeActions.SAVE_ORDER); + // Update the store with information received from the saveOrder response + await baseMixin.methods.dispatchStoreAction(storeActions.UPDATE_STORE_WITH_SAVE_ORDER_RESPONSE, { + referralNumber: savedOrderInfo.data.referralNumber.toString(), + referralCorrelationId: savedOrderInfo.data.referralCorrelationId, + referralDate: savedOrderInfo.data.referralDate, + accountNumber: savedOrderInfo.data.accountNumber.toString(), + saveQuoteId: savedOrderInfo.data.saveQuoteId, + crmCustomerId: savedOrderInfo.data.crmCustomerId.toString(), + }, false); + + // Update the cookie with the referral information when saved. + updateOrCreateFunnelCookie(); } \ No newline at end of file diff --git a/src/helpers/heritage-integration/order-helper.spec.js b/src/helpers/heritage-integration/order-helper.spec.js index 7d769a8d8..c3a581e41 100644 --- a/src/helpers/heritage-integration/order-helper.spec.js +++ b/src/helpers/heritage-integration/order-helper.spec.js @@ -111,9 +111,11 @@ describe("saveOrder", () => { const mockReferralNumber = "2"; const mockCorrelationId = "55"; const mockReferralDate = "2022"; - const mockAccountNumber = "5"; + const mockAccountNumber = "167132"; + const mockSaveQuoteId = "xxx-xxx-xxx"; + const mockCrmCustomerId = "xxx-xxx-xxx" - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber); + const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSaveQuoteId, mockCrmCustomerId); const mockData = { actionList: [ @@ -122,7 +124,7 @@ describe("saveOrder", () => { data: mockOrderInfo, }, { - actionName: storeActions.SET_REFERRAL_INFORMATION + actionName: storeActions.UPDATE_STORE_WITH_SAVE_ORDER_RESPONSE } ] } @@ -134,21 +136,26 @@ describe("saveOrder", () => { // Assert expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.SAVE_ORDER); - expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.SET_REFERRAL_INFORMATION, { + expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(storeActions.UPDATE_STORE_WITH_SAVE_ORDER_RESPONSE, { referralNumber: mockReferralNumber, referralDate: mockReferralDate, referralCorrelationId: mockCorrelationId, - accountNumber: mockAccountNumber + accountNumber: mockAccountNumber, + saveQuoteId: mockSaveQuoteId, + crmCustomerId: mockCrmCustomerId, }, false); }); test("saveOrder => should update DidHeritageFunnelUpdateLast cookie value to false", async () => { // Arrange - const testReferralNumber = 1566818; - const testReferralDate = "2022-03-15T10:56:24.597"; - const testReferralCorrelationId = "404d2b04-f86e-45c3-b373-127b6217b060"; + const mockReferralNumber = 1566818; + const mockReferralDate = "2022-03-15T10:56:24.597"; + const mockReferralCorrelationId = "404d2b04-f86e-45c3-b373-127b6217b060"; + const mockAccountNumber = "167132"; + const mockSaveQuoteId = "xxx-xxx-xxx"; + const mockCrmCustomerId = "xxx-xxx-xxx" - const mockOrderInfo = getMockOrderInfo(testReferralNumber, testReferralCorrelationId, testReferralDate); + const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockReferralCorrelationId, mockReferralDate, mockAccountNumber, mockSaveQuoteId, mockCrmCustomerId); const mockData = { actionList: [{ @@ -161,9 +168,9 @@ describe("saveOrder", () => { setupMocksForJsFiles(mockData); const testCookieValue = { - ReferralNumber: testReferralNumber, - ReferralDate: testReferralDate, - ReferralCorrelationId: testReferralCorrelationId, + ReferralNumber: mockReferralNumber, + ReferralDate: mockReferralDate, + ReferralCorrelationId: mockReferralCorrelationId, ShouldResetState: false, DidHeritageFunnelUpdateLast: true } diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 8faddc1c1..36745d28a 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -90,12 +90,14 @@ export function removeAllTestCookies() { }); } -export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, accountNumber = "0") { +export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, accountNumber = "0", saveQuoteId, crmCustomerId) { return { referralNumber: mockReferralNumber, referralCorrelationId: mockCorrelationId, referralDate: mockReferralDate, - accountNumber: accountNumber + accountNumber: accountNumber, + saveQuoteId: saveQuoteId, + crmCustomerId: crmCustomerId, } } diff --git a/src/router/index.js b/src/router/index.js index c6ce3bd28..8b9328db0 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,6 +1,7 @@ // Supporting files import { createWebHistory, createRouter } from "vue-router"; import { storeActions } from "@/constants/store-actions"; +import { storeMutations } from "../constants/store-mutations"; import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js"; import { routingTable } from "@/router/router-constants/routing-table.js"; import { globalEvents, globalEventTypes } from "@/constants/events"; @@ -113,7 +114,9 @@ const router = createRouter({ //---------------------------------------------------------- Router Functions ---------------------------------------------------------- -router.afterEach(async (to, from) => { +router.afterEach((to, from) => { + // Update lastPageVisited in the store + store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name); // Push page view to GA analyticsMixin.methods.pushPageViewToGA(to.query[queryStrings.FMG_PAGE]); @@ -152,9 +155,9 @@ async function navigate(scenario, currentRoute, optionalQuery = {}, optionalPara // Append page data to the store for the NEXT page, if any. It will be an empty object if none is provided. baseMixin.methods.savePageDataToStore(destinationFmgPageValue, optionalPageData); - // if cookie and referralNumber/Date exists - if (getFunnelCookie()?.ReferralNumber && getFunnelCookie()?.ReferralDate) { - await saveOrder(); + // if cookie and referralNumber/Date exists OR an emailAddress has been saved + if ((getFunnelCookie()?.ReferralNumber && getFunnelCookie()?.ReferralDate) || store.getters.order.customer?.emailAddress) { + saveOrder(); } router.push({ diff --git a/src/store/index.js b/src/store/index.js index a7676a04e..bac95e3cf 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -64,7 +64,11 @@ const getDefaultState = () => { applicationUser: { eventBus: [], pageData: {}, - savedSessionTimeout: getDateForSavedSessionTimeout() + savedSessionTimeout: getDateForSavedSessionTimeout(), + saveOrderPromise: null, + saveQuoteId: null, + crmCustomerId: null, + lastPageVisited: null, }, } }; @@ -200,6 +204,19 @@ export const mutations = { state.order.serviceLocation.zipCode = serviceLocationInfo.zipCode; }, + // applicationUser MUTATIONS + updateSaveOrderPromise(state, saveOrderPromise){ + state.applicationUser.saveOrderPromise = saveOrderPromise; + }, + updateSaveQuoteId(state, saveQuoteId) { + state.applicationUser.saveQuoteId = saveQuoteId; + }, + updateCrmCustomerId(state, crmCustomerId) { + state.applicationUser.crmCustomerId = crmCustomerId; + }, + updateLastPageVisited(state, lastPageVisited) { + state.applicationUser.lastPageVisited = lastPageVisited + }, // EVENT BUS MUTATIONS addEventToBus(state, event) { state.applicationUser.eventBus.push(event); @@ -476,6 +493,17 @@ export const actions = { } }); }, + + // Misc Actions + updateStoreWithSaveOrderResponse(context, { referralNumber, referralDate, referralCorrelationId, accountNumber, saveQuoteId, crmCustomerId }) { + context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber); + context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate); + context.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, referralCorrelationId); + context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, accountNumber); + context.commit(storeMutations.UPDATE_SAVE_QUOTE_ID, saveQuoteId); + context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId); + }, + logPageView(context, { userId, sessionKey, pageName, sessionId, action, event, shouldUseSessionId }) { var payload = { userId: userId, @@ -612,6 +640,7 @@ export const actions = { const vehicle = context.getters.vehicle; const damage = context.getters.damage; const order = context.state.order; + const applicationUser = context.getters.applicationUser; return globalMethods.callHttpClient({ method: endpoints.SaveOrder.method, @@ -650,7 +679,12 @@ export const actions = { }, referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place referralDate: order.referralDate, - accountNumber: order.accountNumber?.toString() + accountNumber: order.accountNumber?.toString(), + existingPromoCode: null, + lastPage: applicationUser.lastPageVisited, + crmCustomerId: applicationUser.crmCustomerId, + saveQuoteId: applicationUser.saveQuoteId, + }, }); }, diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 960a6d784..a9e37dea7 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -571,12 +571,17 @@ describe("Actions", () => { registration: {} }, damage: {}, + applicationUser: { + lastPageVisited: "test-page", + crmCustomerId: "xxx-xxx-xxx", + saveQuoteId: "xxx-xxx-xxx" + } }; context.state = { order: { serviceLocation: {}, customer: {} - } + }, }; globalMethods.callHttpClient.mockImplementation(() => { @@ -611,7 +616,7 @@ describe("Actions", () => { expect(commit).toBeCalledWith(storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION, { "referralNumber": 123 }); }); - it("setReferralInformation, should call commit three times", () => { + it("updateStoreWithSaveOrderResponse, should call commit six times", () => { // Arrange const context = state; const commit = jest.fn(); @@ -619,12 +624,23 @@ describe("Actions", () => { context.commit = commit; // Act - actions.setReferralInformation(context, { referralNumber: "123", referralDate: new Date().toUTCString(), referralCorrelationId: "xxx-xxx-xxx" }); + actions.updateStoreWithSaveOrderResponse(context, + { + referralNumber: "123", + referralDate: new Date().toUTCString(), + referralCorrelationId: "xxx-xxx-xxx", + accountNumber: "167132", + saveQuoteId: "xxx-xxx-xxx", + crmCustomerId: "xxx-xxx-xxx", + }); // Assert expect(commit).toBeCalledWith(storeMutations.UPDATE_REFERRAL_NUMBER, "123"); expect(commit).toBeCalledWith(storeMutations.UPDATE_REFERRAL_DATE, new Date().toUTCString()); expect(commit).toBeCalledWith(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, "xxx-xxx-xxx"); + expect(commit).toBeCalledWith(storeMutations.UPDATE_PARENT_ACCT_NUMBER, "167132"); + expect(commit).toBeCalledWith(storeMutations.UPDATE_SAVE_QUOTE_ID, "xxx-xxx-xxx"); + expect(commit).toBeCalledWith(storeMutations.UPDATE_CRM_CUSTOMER_ID, "xxx-xxx-xxx"); }); it("logPageView action, should return nothing", async () => {