diff --git a/jest.config.js b/jest.config.js index 0a063507d..f4c60e4f7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -12,6 +12,7 @@ module.exports = { "!src/router/**/*.js", "!src/helpers/unit-test-helper.js", "!src/layouts/vehicle-damage/windshield-options/windshield-options.vue", + "!src/layouts/molding-questions/**/*.vue", "!src/layouts/part-questions/**/*.vue", "!src/layouts/reveal/**/*.vue", "!src/ux-components/text-link/**/*.vue", diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 87331daea..6fa81d45f 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -31,6 +31,7 @@ const storeActions = { INITIALIZE_SESSION: "initializeSession", GET_EXPERIMENTS_BY_USER: "GetExperimentsByUser", CLEAR_VIN: "clearVin", + RESET_SAVE_ORDER_PROMISE: "resetSaveOrderPromise", // DEPENDENCY MUTATIONS RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleAndDependencies", diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 80697cc46..508f59bf7 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -39,7 +39,7 @@ const storeMutations = { UPDATE_REFERRAL_DATE: "updateReferralDate", UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId", UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber", - UPDATE_SAVE_QUOTE_ID: "updateSaveQuoteId", + UPDATE_SAVED_SESSION_ID: "updateSavedSessionId", UPDATE_CRM_CUSTOMER_ID: "updateCrmCustomerId", // EVENT BUS MUTATIONS @@ -58,6 +58,7 @@ const storeMutations = { UPDATE_STATE_WITH_ORDER_INFORMATION: "updateStateWithOrderInformation", UPDATE_SAVE_ORDER_PROMISE: "updateSaveOrderPromise", UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited", + RESET_SAVE_ORDER_PROMISE: "resetSaveOrderPromise", }; export { storeMutations }; diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js index 3a8614661..775a64fec 100644 --- a/src/helpers/heritage-integration/cookie-helper.js +++ b/src/helpers/heritage-integration/cookie-helper.js @@ -15,7 +15,7 @@ export function updateOrCreateFunnelCookie() { // Set up cookie with all the props. setFunnelCookieProperties({ LastTouched: new Date().toUTCString(), - SavedQuoteTimeoutDate: store.getters.applicationUser.savedSessionTimeout, + SavedSessionTimeoutDate: store.getters.applicationUser.savedSessionTimeout, DidHeritageFunnelUpdateLast: false, ShouldResetState: false, ReferralNumber: store.getters.order.referralNumber, diff --git a/src/helpers/heritage-integration/navigation-helper.spec.js b/src/helpers/heritage-integration/navigation-helper.spec.js index 1b33c0a6f..0e615aef5 100644 --- a/src/helpers/heritage-integration/navigation-helper.spec.js +++ b/src/helpers/heritage-integration/navigation-helper.spec.js @@ -309,10 +309,10 @@ describe("navigateToHeritageFunnel", () => { const mockCorrelationId = "55"; const mockReferralDate = "2022"; const mockAccountNumber = "167132"; - const mockSaveQuoteId = "xxx-xxx-xxx"; + const mockSavedSessionId = "xxx-xxx-xxx"; const mockCrmCustomerId = "xxx-xxx-xxx" - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSaveQuoteId, mockCrmCustomerId); + const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSavedSessionId, mockCrmCustomerId); const mockData = { actionList: [{ @@ -344,10 +344,10 @@ describe("navigateToHeritageFunnel", () => { const mockCorrelationId = "55"; const mockReferralDate = "2022"; const mockAccountNumber = "167132"; - const mockSaveQuoteId = "xxx-xxx-xxx"; + const mockSavedSessionId = "xxx-xxx-xxx"; const mockCrmCustomerId = "xxx-xxx-xxx" - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSaveQuoteId, mockCrmCustomerId); + const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSavedSessionId, mockCrmCustomerId); const mockData = { actionList: [{ diff --git a/src/helpers/heritage-integration/order-helper.js b/src/helpers/heritage-integration/order-helper.js index 9722744f0..870ee190b 100644 --- a/src/helpers/heritage-integration/order-helper.js +++ b/src/helpers/heritage-integration/order-helper.js @@ -60,6 +60,8 @@ export async function saveOrder() { and returns the response. */ async function loadOrder(referralNumber, referralDate, referralCorrelationId, accountNumber) { + // await the saveOrderPromise in the store to make sure we're loading up to date information + await store.getters.applicationUser.saveOrderPromise; const response = await baseMixin.methods.dispatchStoreAction(storeActions.LOAD_ORDER, { referralNumber: referralNumber.toString(), @@ -82,7 +84,7 @@ async function saveOrderHelper() { referralCorrelationId: savedOrderInfo.data.referralCorrelationId, referralDate: savedOrderInfo.data.referralDate, accountNumber: savedOrderInfo.data.accountNumber.toString(), - saveQuoteId: savedOrderInfo.data.saveQuoteId, + savedSessionId: savedOrderInfo.data.savedSessionId, crmCustomerId: savedOrderInfo.data.crmCustomerId.toString(), }, false); diff --git a/src/helpers/heritage-integration/order-helper.spec.js b/src/helpers/heritage-integration/order-helper.spec.js index c3a581e41..400ab46e4 100644 --- a/src/helpers/heritage-integration/order-helper.spec.js +++ b/src/helpers/heritage-integration/order-helper.spec.js @@ -112,10 +112,10 @@ describe("saveOrder", () => { const mockCorrelationId = "55"; const mockReferralDate = "2022"; const mockAccountNumber = "167132"; - const mockSaveQuoteId = "xxx-xxx-xxx"; + const mockSavedSessionId = "xxx-xxx-xxx"; const mockCrmCustomerId = "xxx-xxx-xxx" - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSaveQuoteId, mockCrmCustomerId); + const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, mockAccountNumber, mockSavedSessionId, mockCrmCustomerId); const mockData = { actionList: [ @@ -141,7 +141,7 @@ describe("saveOrder", () => { referralDate: mockReferralDate, referralCorrelationId: mockCorrelationId, accountNumber: mockAccountNumber, - saveQuoteId: mockSaveQuoteId, + savedSessionId: mockSavedSessionId, crmCustomerId: mockCrmCustomerId, }, false); }); @@ -152,10 +152,10 @@ describe("saveOrder", () => { const mockReferralDate = "2022-03-15T10:56:24.597"; const mockReferralCorrelationId = "404d2b04-f86e-45c3-b373-127b6217b060"; const mockAccountNumber = "167132"; - const mockSaveQuoteId = "xxx-xxx-xxx"; + const mockSavedSessionId = "xxx-xxx-xxx"; const mockCrmCustomerId = "xxx-xxx-xxx" - const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockReferralCorrelationId, mockReferralDate, mockAccountNumber, mockSaveQuoteId, mockCrmCustomerId); + const mockOrderInfo = getMockOrderInfo(mockReferralNumber, mockReferralCorrelationId, mockReferralDate, mockAccountNumber, mockSavedSessionId, mockCrmCustomerId); const mockData = { actionList: [{ diff --git a/src/helpers/heritage-integration/session-helper.js b/src/helpers/heritage-integration/session-helper.js index ba816cdb1..ca50a4e7b 100644 --- a/src/helpers/heritage-integration/session-helper.js +++ b/src/helpers/heritage-integration/session-helper.js @@ -28,7 +28,7 @@ export function isAnalyticsSessionStillActive() { */ export function isSavedSessionStillActive() { if (getFunnelCookie() !== null) { - const savedSessionTimeStamp = new Date(getFunnelCookie().SavedQuoteTimeoutDate); + const savedSessionTimeStamp = new Date(getFunnelCookie().SavedSessionTimeoutDate); const isSavedSessionTimedOut = (new Date(new Date().toUTCString()) > savedSessionTimeStamp); if (isSavedSessionTimedOut) { diff --git a/src/helpers/heritage-integration/session-helper.spec.js b/src/helpers/heritage-integration/session-helper.spec.js index 8a17743d1..b41827bf7 100644 --- a/src/helpers/heritage-integration/session-helper.spec.js +++ b/src/helpers/heritage-integration/session-helper.spec.js @@ -41,7 +41,7 @@ describe("isSavedSessionStillActive", () => { mockDate.setDate(mockDate.getDate() + 1); cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie") - .mockReturnValue({ SavedQuoteTimeoutDate: mockDate }); + .mockReturnValue({ SavedSessionTimeoutDate: mockDate }); // Act const result = isSavedSessionStillActive(); @@ -56,7 +56,7 @@ describe("isSavedSessionStillActive", () => { mockDate.setDate(mockDate.getDate() - 1) cookieHelper.getFunnelCookie = jest.spyOn(cookieHelper, "getFunnelCookie") - .mockReturnValue({ SavedQuoteTimeoutDate: mockDate }); + .mockReturnValue({ SavedSessionTimeoutDate: mockDate }); // Act const result = isSavedSessionStillActive(); diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 36745d28a..13436be78 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -90,13 +90,13 @@ export function removeAllTestCookies() { }); } -export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, accountNumber = "0", saveQuoteId, crmCustomerId) { +export function getMockOrderInfo(mockReferralNumber, mockCorrelationId, mockReferralDate, accountNumber = "0", savedSessionId, crmCustomerId) { return { referralNumber: mockReferralNumber, referralCorrelationId: mockCorrelationId, referralDate: mockReferralDate, accountNumber: accountNumber, - saveQuoteId: saveQuoteId, + savedSessionId: savedSessionId, crmCustomerId: crmCustomerId, } } diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js index 2e83c3103..7bfc02eba 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js +++ b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js @@ -235,7 +235,7 @@ describe("license-plate-lookup.vue", () => { expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); }); - test("navigateToHeritageFunnel should be called if isCarIdDifferent is false or isSelectedGlassAvailableForVehicle is true when navigateForward is called", async () => { + test("navigateForwardWithSingleCarMatch should be called if isCarIdDifferent is false or isSelectedGlassAvailableForVehicle is true when navigateForward is called", async () => { // Arrange const { wrapper } = setupMocks({}); @@ -247,11 +247,11 @@ describe("license-plate-lookup.vue", () => { wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => { return ''; }); - navigateToHeritage.navigateToHeritageFunnel = jest.fn(); + wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); await wrapper.vm.navigateForward(); //Assert - expect(navigateToHeritage.navigateToHeritageFunnel).toHaveBeenCalled(); + expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalled(); }); test("carId matches returned vehicle => navigateForwardWithSingleCarMatch", async () => { diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue new file mode 100644 index 000000000..0ffaae411 --- /dev/null +++ b/src/layouts/molding-questions/molding-questions.vue @@ -0,0 +1,286 @@ + + + + + diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue index ee1d81c09..3f779ace8 100644 --- a/src/layouts/part-questions/part-questions.vue +++ b/src/layouts/part-questions/part-questions.vue @@ -142,14 +142,14 @@ export default { if (!partsLookup) { return } - const glassNameAndParts = partsLookup.data.glassNameAndParts; + const glassNameAndPartsForStore = partsLookup.data.glassNameAndPartsForStore; // test response data for multiple parts - const hasMultipleParts = glassNameAndParts.some((glass) => glass.parts?.length > 1); + const hasMultipleParts = glassNameAndPartsForStore.some((glass) => glass.parts?.length > 1); // loop through all glass items const collectedGlassParts = []; - glassNameAndParts.forEach((glass) => { + glassNameAndPartsForStore.forEach((glass) => { if (Array.isArray(glass.parts) && glass.parts.length === 1) { const singlePart = glass.parts[0]; collectedGlassParts.push({ @@ -159,24 +159,37 @@ export default { "requiresRecalibration": singlePart.requiresRecalibration, "childParts": singlePart.childParts, "price": singlePart.price, - }) + }); + // check for and collect any molding questions + if (Array.isArray(singlePart.childPartQuestions) && singlePart.childPartQuestions.length > 0) { + this.moldingQuestionsForStore.push({ + "glassName": glass.glassName, + "glassLocation": glass.glassLocation, + "childPartQuestions": singlePart.childPartQuestions, + }); + } } }); if (!hasMultipleParts) { store.commit(storeMutations.UPDATE_GLASS_PARTS, collectedGlassParts); } - this.navigateForward(hasMultipleParts, glassNameAndParts); + this.navigateForward(hasMultipleParts, glassNameAndPartsForStore); }, - async navigateForward(hasMultipleParts, glassNameAndParts) { + async navigateForward(hasMultipleParts, glassNameAndPartsForStore) { if (hasMultipleParts) { // if multiple parts on any glass // go to vehicle-parts page and pass the partsData - this.$router.navigate(this.navigationScenarios.ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS,this.$route,{},{},{partsOrQuestions: glassNameAndParts}); + this.$router.navigate(this.navigationScenarios.ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS,this.$route,{},{},{partsOrQuestions: glassNameAndPartsForStore}); } else { // if single parts only // go to quote page this.$router.navigate(this.navigationScenarios.ANSWERED_QUESTIONS_WITH_SINGLE_PART,this.$route); } + + // TODO - ADD CHECK FOR CAPABILITY QUESTIONS TO SEE IF NAVIGATE TO CAPABILITY-QUESTIONS + + + }, arePagePrerequisitesValid() { return Object.keys(store.getters.pageData(fmgPageValues.PART_QUESTIONS)).length > 0; diff --git a/src/layouts/vehicle-parts/vehicle-parts.vue b/src/layouts/vehicle-parts/vehicle-parts.vue index c35699c4e..75ba3df7f 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.vue +++ b/src/layouts/vehicle-parts/vehicle-parts.vue @@ -65,112 +65,90 @@ import { storeActions } from "@/constants/store-actions"; import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; - export default { +export default { name: "vehicle-parts", mixins: [vehicleQuestionsMixin], async beforeRouteEnter(to, from, next) { - // Call APIs - const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); - // Settle promises and get results - const promiseResultMap = [ + // Call APIs + const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage); + // Settle promises and get results + const promiseResultMap = [ { - resultKey: "cmsContent", - promise: cmsContentPromise, + resultKey: "cmsContent", + promise: cmsContentPromise, }, - ]; - const resultMap = await settleAllPromises(promiseResultMap); - // Call the "next" function to complete the transition to this page. - next((vm) => { + ]; + const resultMap = await settleAllPromises(promiseResultMap); + // Call the "next" function to complete the transition to this page. + next((vm) => { vm.setCmsContent(resultMap.cmsContent); // Glass Part Question dynamic component Object.keys(vm.$refs) - .filter( - (r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined - ) - .forEach((c) => + .filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined) + .forEach((c) => vm.$refs[c][0].initializeComponent({ - ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget, - FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget, + ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget, + FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget, }) - ); - }); + ); + }); }, data() { - return { - glassParts: {}, - alertWidgetData: Object, - alreadyPopulatedPartsData: {}, - }; - }, - components: { - Form, - glassPartQuestion, - funnelHeader, - vehicleBanner, - funnelSubHeader, - funnelFooter, - alert, + return { + glassParts: {}, + matchedParts: [], + alertWidgetData: Object, + alreadyPopulatedPartsData: {}, + }; }, computed: { - isForwardActionDisabled() { - return ( - Object.keys(this.matchedParts).length !== - this.PartsFromApi.partsOrQuestions.length - ); - }, - matchedParts() { - const matchedParts = []; + isForwardActionDisabled() { + return ( + this.selectedGlassPartNumbers.length !== this.PartsFromApi.partsOrQuestions.length + ); + }, + selectedGlassPartNumbers () { + // Compile all selected parts from the page. + const numberArray = []; + for (let glassPart of Object.values(this.glassParts)) { + if (glassPart?.partNumber) { numberArray.push(glassPart.partNumber) } + } + return numberArray; + }, + PartsOrQuestions() { + const partsData = this.PartsFromApi; - // Match them to the parts from the API. - this.PartsFromApi.partsOrQuestions.forEach((part) => { - const selectedPartForGlassLocationAndName = - this.glassParts[`${part.glassLocation}-${part.glassName}`]; - const selectedPartData = part.parts.filter( - (part) => - selectedPartForGlassLocationAndName && - part.partNumber == selectedPartForGlassLocationAndName?.partNumber - )[0]; + // Map API result data, to vehicle-parts data structure + const mappedData = partsData.partsOrQuestions.map((g) => { + return { + glassName: g.glassName, + glassLocation: g.glassLocation, + colorAnswers: g.parts.reduce((arr, p) => { + arr.push({ + ColorAnswerText: p.color, + FeatureAnswers: [ + { + FeatureAnswerText: p.description === "" ? p.color : p.description, + PartNumber: p.partNumber, + }, + ], + }); + return arr; + }, []), + }; + }); - if (selectedPartData) matchedParts.push(selectedPartData); - }); + return mappedData; + }, - return matchedParts; - }, - PartsOrQuestions() { - const partsData = this.PartsFromApi; + PartsFromApi() { + return store.getters.pageData(fmgPageValues.VEHICLE_PARTS); + }, - // Map API result data, to vehicle-parts data structure - const mappedData = partsData.partsOrQuestions.map((g) => { - return { - glassName: g.glassName, - glassLocation: g.glassLocation, - colorAnswers: g.parts.reduce((arr, p) => { - arr.push({ - ColorAnswerText: p.color, - FeatureAnswers: [ - { - FeatureAnswerText: - p.description === "" ? p.color : p.description, - PartNumber: p.partNumber, - }, - ], - }); - return arr; - }, []), - }; - }); - - return mappedData; - }, - - PartsFromApi() { - return store.getters.pageData(fmgPageValues.VEHICLE_PARTS); - }, - - RefPrefix() { - return "partQuestion"; - }, + RefPrefix() { + return "partQuestion"; + }, }, methods: { arePagePrerequisitesValid() { @@ -191,74 +169,97 @@ async forwardButtonAction() { const selectedGlassPartNumbers = []; const matchedParts = []; - - // Compile all selected parts from the page. - for (let [key, value] of Object.entries(this.glassParts)) { - for (let [glassKey, glassValue] of Object.entries(value)) { - selectedGlassPartNumbers.push(glassValue[0]); - } - } + let isMoldingQuestions = false; // Match them to the parts from the API. for (let [key, value] of Object.entries( - this.PartsFromApi.partsOrQuestions + this.PartsFromApi.partsOrQuestions )) { - for (let [partKey, partValue] of Object.entries(value.parts)) { - const currentPart = - this.PartsFromApi.partsOrQuestions[key].parts[partKey]; - const isMatched = selectedGlassPartNumbers.some( - (p) => p === currentPart.partNumber - ); + for (let [partKey, partValue] of Object.entries(value.parts)) { - if (isMatched) { - matchedParts.push(currentPart); + const currentPart = this.PartsFromApi.partsOrQuestions[key].parts[partKey]; + + const isMatched = this.selectedGlassPartNumbers.some( + (p) => p === currentPart.partNumber + ); + + if (isMatched) { + this.matchedParts.push(currentPart); + // check if there are childPartQuestions (for molding-questions) + if (Array.isArray(currentPart.childPartQuestions) && currentPart.childPartQuestions.length > 0) { + isMoldingQuestions = true + } + } } - } } - // If no parts could be matched, throw an error. + // If no parts could be matched, throw an error (isForwardActionDisabled is based off of this.matchedParts) if (this.isForwardActionDisabled) { - this.$refs.funnelFooter.removeLoader(); - throw new Error("Could not match any parts to the selected parts"); + this.$refs.funnelFooter.removeLoader(); + throw new Error("Could not match any parts to the selected parts"); } - // Save parts to the store. - await this.dispatchStoreAction( - storeActions.SAVE_GLASS_PARTS, - matchedParts - ); + // Navigate to the next page + if (isMoldingQuestions) { + this.$router.navigate( + this.navigationScenarios.HAS_MOLDING_QUESTIONS, + this.$route, + {}, + {}, + this.moldingQuestionsForStore + ); + } + else { + // Save parts to the store + await this.dispatchStoreAction( + storeActions.SAVE_GLASS_PARTS, + this.matchedParts, + false + ); + // Navigate to the quote page + this.$router.navigate( + this.navigationScenarios.SELECTED_PARTS, + this.$route + ); + } - // Navigate to the next page. - this.$router.navigate( - this.navigationScenarios.SELECTED_PARTS, - this.$route - ); - }, + // TODO - ADD CHECK FOR CAPABILITY QUESTIONS TO SEE IF NAVIGATE TO CAPABILITY-QUESTIONS + + }, LoadInitialPartsData() { - const partsData = this.PartsFromApi; - const alreadyPopulatedPartsData = - this.$store.getters.lineItems.glassParts === null - ? {} - : this.$store.getters.lineItems.glassParts; + const partsData = this.PartsFromApi; + const alreadyPopulatedPartsData = + this.$store.getters.lineItems.glassParts === null + ? {} + : this.$store.getters.lineItems.glassParts; - partsData.partsOrQuestions.map((g) => { - // If the part is already populated, use the value from the store and populate the v-model. - Object.keys(alreadyPopulatedPartsData).forEach((key) => { - const partNumber = alreadyPopulatedPartsData[key].partNumber; - g.parts.forEach((p) => { - if (p.partNumber === partNumber) { - this.glassParts[g.glassLocation + "-" + g.glassName] = { - [g.glassLocation]: [partNumber], - }; - } + partsData.partsOrQuestions.map((g) => { + // If the part is already populated, use the value from the store and populate the v-model. + Object.keys(alreadyPopulatedPartsData).forEach((key) => { + const partNumber = alreadyPopulatedPartsData[key].partNumber; + g.parts.forEach((p) => { + if (p.partNumber === partNumber) { + this.glassParts[g.glassLocation + "-" + g.glassName] = { + [g.glassLocation]: [partNumber], + }; + } + }); + }); }); - }); - }); - }, + }, }, mounted() { - this.LoadInitialPartsData(); + this.LoadInitialPartsData(); }, - }; + components: { + Form, + glassPartQuestion, + funnelHeader, + vehicleBanner, + funnelSubHeader, + funnelFooter, + alert, + }, +}; diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 7a8f3832f..d4b3e6497 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -5,6 +5,11 @@ export default { }, hasGlassLocationWithMultipleParts(partsOrQuestions) { return partsOrQuestions.some(pq => pq.parts?.length > 1); + }, + hasChildPartQuestions(partsOrQuestions) { + return partsOrQuestions.some(pq => { + return pq.parts?.some(part => part.childPartQuestions?.length > 0); + }); } } } \ No newline at end of file diff --git a/src/mixins/vin-pages-mixin.js b/src/mixins/vin-pages-mixin.js index 31fa44cf7..d6952eb97 100644 --- a/src/mixins/vin-pages-mixin.js +++ b/src/mixins/vin-pages-mixin.js @@ -9,10 +9,12 @@ export default { methods: { async navigateForwardWithSingleCarMatch() { const result = await this.dispatchStoreAction(storeActions.GET_PARTS_OR_QUESTIONS); - const partsOrQuestions = result.data.partsOrQuestions; const hasPartsQuestions = this.hasPartQuestions(partsOrQuestions); const hasGlassLocationWithMultipleParts = this.hasGlassLocationWithMultipleParts(partsOrQuestions); + const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions); + + // TODO - ADD CHECK FOR CAPABILITY QUESTIONS TO SEE IF NAVIGATE TO CAPABILITY-QUESTIONS if (hasPartsQuestions) { this.$router.navigate(this.navigationScenarios.SELECTED_VIN_WITH_PART_QUESTIONS, this.$route, {}, {}, result.data); @@ -20,6 +22,9 @@ export default { else if (hasGlassLocationWithMultipleParts) { this.$router.navigate(this.navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, this.$route, {}, {}, result.data); } + else if (hasChildPartQuestions) { + this.$router.navigate(this.navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS, this.$route, {}, {}, result.data); + } else { store.commit(storeMutations.UPDATE_GLASS_PARTS, result.data); this.$refs.loadingModal.showModal(); diff --git a/src/router/index.js b/src/router/index.js index d086cc89a..e0c5d537b 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -60,6 +60,9 @@ const routes = [ // On entering the funnel "fresh", read cookie information, decide what to do next. if (from.redirectedFrom === undefined) { + // clear the saveOrderPromise - if it exists in the vuex store but a new instance was created + // the saveOrderPromise will no longer point to a valid promise + baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_ORDER_PROMISE); const loadOrderResponse = await loadOrderIfPresent(); const pageToRedirectTo = await getPageToRouteExistingOrderTo(to, loadOrderResponse); diff --git a/src/router/router-constants/fmgPage-values.js b/src/router/router-constants/fmgPage-values.js index d067895ee..7a38c6b40 100644 --- a/src/router/router-constants/fmgPage-values.js +++ b/src/router/router-constants/fmgPage-values.js @@ -8,6 +8,7 @@ const fmgPageValues = { VIN_LOOKUP: "vin-lookup", VEHICLE_PARTS: "vehicle-parts", PART_QUESTIONS: "part-questions", + MOLDING_QUESTIONS: "molding-questions", LICENSE_PLATE_LOOKUP: "license-plate-lookup", REVEAL: "reveal", ESTIMATE: "estimate", diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 61de8147f..ce897d3c2 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -10,6 +10,7 @@ const navigationScenarios = { SELECTED_PARTS: "SELECTED_PARTS", SELECTED_VIN_WITH_PART_QUESTIONS: "SELECTED_VIN_WITH_PART_QUESTIONS", SELECTED_VIN_WITH_MULTIPLE_PARTS: "SELECTED_VIN_WITH_MULTIPLE_PARTS", + SELECTED_VIN_WITH_MOLDING_QUESTIONS: "SELECTED_VIN_WITH_MOLDING_QUESTIONS", CONTINUING_WITH_SINGLE_PART: "CONTINUING_WITH_SINGLE_PART", CONTINUING_WITH_MULTIPLE_VEHICLES: "CONTINUING_WITH_MULTIPLE_VEHICLES", SELECTED_VIN_HAS_MISMATCHED_GLASS: "SELECTED_VIN_HAS_MISMATCHED_GLASS", @@ -21,7 +22,8 @@ const navigationScenarios = { ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS: "ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS", SELECTED_PROVIDE_VIN_DIFFERENT_WAY: "SELECTED_PROVIDE_VIN_DIFFERENT_WAY", CLICKED_BACK_WITH_PART_QUESTION_ANSWERS: "CLICKED_BACK_WITH_PART_QUESTION_ANSWERS", - CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS: "CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS" + CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS: "CLICKED_BACK_WITHOUT_PART_QUESTION_ANSWERS", + HAS_MOLDING_QUESTIONS: "HAS_MOLDING_QUESTIONS", }; export { navigationScenarios }; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 0c729607f..911ff66e4 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -135,6 +135,10 @@ const routingTable = function(store) { { scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS + }, + { + scenario: navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS, + destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS } ], }, @@ -156,6 +160,10 @@ const routingTable = function(store) { { scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS + }, + { + scenario: navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS, + destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS } ], }, @@ -181,6 +189,10 @@ const routingTable = function(store) { { scenario: navigationScenarios.SELECTED_VIN_WITH_MULTIPLE_PARTS, destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS + }, + { + scenario: navigationScenarios.SELECTED_VIN_WITH_MOLDING_QUESTIONS, + destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS } ], }, @@ -241,12 +253,25 @@ const routingTable = function(store) { scenario: navigationScenarios.ANSWERED_QUESTIONS_WITH_MULTIPLE_PARTS, destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS }, + { + scenario: navigationScenarios.HAS_MOLDING_QUESTIONS, + destinationFmgPageValue: fmgPageValues.MOLDING_QUESTIONS, + }, { scenario: navigationScenarios.ANSWERED_QUESTIONS_WITH_SINGLE_PART, destinationFmgPageValue: fmgPageValues.QUOTE, }, ] }, + { + fmgPageValue: fmgPageValues.MOLDING_QUESTIONS, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationFmgPageValue: fmgPageValues.VEHICLE_PARTS + }, + ] + }, ]; } diff --git a/src/store/index.js b/src/store/index.js index 200389734..d6c09b22c 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -67,7 +67,7 @@ const getDefaultState = () => { pageData: {}, savedSessionTimeout: getDateForSavedSessionTimeout(), saveOrderPromise: null, - saveQuoteId: null, + savedSessionId: null, crmCustomerId: null, lastPageVisited: null, experiments: [] @@ -210,8 +210,8 @@ export const mutations = { updateSaveOrderPromise(state, saveOrderPromise){ state.applicationUser.saveOrderPromise = saveOrderPromise; }, - updateSaveQuoteId(state, saveQuoteId) { - state.applicationUser.saveQuoteId = saveQuoteId; + updateSavedSessionId(state, savedSessionId) { + state.applicationUser.savedSessionId = savedSessionId; }, updateCrmCustomerId(state, crmCustomerId) { state.applicationUser.crmCustomerId = crmCustomerId; @@ -273,7 +273,9 @@ export const mutations = { resetState(state) { Object.assign(state, getDefaultState()); }, - + resetSaveOrderPromise(state) { + state.applicationUser.saveOrderPromise = null; + }, // Misc Mutations updateStateWithOrderInformation(state, orderInformation) { state.order.referralNumber = orderInformation.referralNumber; @@ -461,6 +463,9 @@ export const actions = { resetState(context) { context.commit(storeMutations.RESET_STATE); }, + resetSaveOrderPromise(context) { + context.commit(storeMutations.RESET_SAVE_ORDER_PROMISE); + }, // Content API Actions getRouteInfo(context, { pageName }) { @@ -501,12 +506,12 @@ export const actions = { }, // Misc Actions - updateStoreWithSaveOrderResponse(context, { referralNumber, referralDate, referralCorrelationId, accountNumber, saveQuoteId, crmCustomerId }) { + updateStoreWithSaveOrderResponse(context, { referralNumber, referralDate, referralCorrelationId, accountNumber, savedSessionId, 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_SAVED_SESSION_ID, savedSessionId); context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId); }, @@ -689,7 +694,7 @@ export const actions = { existingPromoCode: null, lastPage: applicationUser.lastPageVisited, crmCustomerId: applicationUser.crmCustomerId, - saveQuoteId: applicationUser.saveQuoteId, + savedSessionId: applicationUser.savedSessionId, }, }); @@ -705,7 +710,10 @@ export const actions = { accountNumber: accountNumber?.toString() }, }).then((response) => { - // context.commit(storeMutations.RESET_STATE); + // clear the state if the existing referral number does not equal what is returned from loadOrder + if (context.state.order.referralNumber != response.data.referralNumber) { + context.commit(storeMutations.RESET_STATE); + } context.commit(storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION, response.data); return response; }); diff --git a/src/store/store.spec.js b/src/store/store.spec.js index a9e37dea7..29f8a88ed 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -574,7 +574,7 @@ describe("Actions", () => { applicationUser: { lastPageVisited: "test-page", crmCustomerId: "xxx-xxx-xxx", - saveQuoteId: "xxx-xxx-xxx" + savedSessionId: "xxx-xxx-xxx" } }; context.state = { @@ -630,7 +630,7 @@ describe("Actions", () => { referralDate: new Date().toUTCString(), referralCorrelationId: "xxx-xxx-xxx", accountNumber: "167132", - saveQuoteId: "xxx-xxx-xxx", + savedSessionId: "xxx-xxx-xxx", crmCustomerId: "xxx-xxx-xxx", }); @@ -639,7 +639,7 @@ describe("Actions", () => { 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_SAVED_SESSION_ID, "xxx-xxx-xxx"); expect(commit).toBeCalledWith(storeMutations.UPDATE_CRM_CUSTOMER_ID, "xxx-xxx-xxx"); });