diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index aeb38d792..3024a67d9 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -62,6 +62,18 @@ const endpoints = { url: "/parts/api/v1/parts/parts", method: "POST", }, + GetWipers: { + url: "/parts/api/v1/parts/wipers", + method: "GET", + }, + GetRainDefense: { + url: "/parts/api/v1/parts/rain-defense", + method: "GET", + }, + GetSupportingItems: { + url: "/parts/api/v1/parts/supporting-items", + method: "POST", + }, GetCapabilityQuestions: { url: "/parts/api/v1/parts/capability-questions", method: "GET", @@ -82,6 +94,10 @@ const endpoints = { url: "/location/api/v1/location/zip", method: "GET", }, + PriceOrderItems: { + url: "/price/api/v1/price/order-items", + method: "POST", + }, LogExperimentExposureIfAssigned: { url: "/experiments/api/v1/experiments/log-exposure", method: "POST", diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 78053b567..11e2ae4c5 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -20,6 +20,9 @@ const storeActions = { LOOKUP_VIN_BY_ADDRESS: "lookupVinByAddress", GET_PARTS_OR_QUESTIONS: "getPartsOrQuestions", GET_PARTS: "getParts", + GET_WIPERS: "getWipers", + GET_RAIN_DEFENSE: "getRainDefense", + GET_SUPPORTING_ITEMS: "getSupportingItems", GET_CAPABILITY_QUESTIONS: "getCapabilityQuestions", GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: "getPartFromCapabilityQuestionAnswer", GET_MOLDING_QUESTIONS: "getMoldingQuestions", @@ -27,6 +30,7 @@ const storeActions = { LOAD_SESSION: "loadSession", UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE: "updateStoreWithSaveSessionResponse", VALIDATE_ZIP: "validateZip", + PRICE_ORDER_ITEMS: "priceOrderItems", LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure", LOG_PAGE_VIEW: "logPageView", LOG_CUSTOM_EVENT: "logCustomEvent", diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 768826c27..5c903ea7e 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -57,7 +57,9 @@ import textBlock from "@/common-components/text-block/text-block"; import modal from "@/common-components/modal/modal"; import baseMixin from "@/mixins/base-mixin.js"; import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin"; - +import { settleAllPromises } from "@/helpers/layout-helper"; +import { storeActions } from "@/constants/store-actions"; +import store from "@/store"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { Form } from "vee-validate"; @@ -66,70 +68,48 @@ export default { async beforeRouteEnter(to, from, next) { // Call APIs const cmsContent = await fetchCmsContentForPage(to.query.fmgPage); + const wipersPromise = baseMixin.methods.dispatchStoreAction(storeActions.GET_WIPERS); + const rainDefensePromise = baseMixin.methods.dispatchStoreAction( + storeActions.GET_RAIN_DEFENSE + ); + const supportingItemsPromise = baseMixin.methods.dispatchStoreAction( + storeActions.GET_SUPPORTING_ITEMS + ); - // TODOS - modify as needed, just a rough sketch to place initializations + const promiseResultMap = [ + { + resultKey: "wipers", + promise: wipersPromise, + }, + { + resultKey: "rainDefense", + promise: rainDefensePromise, + }, + { + resultKey: "supportingItems", + promise: supportingItemsPromise, + }, + ]; - // get supporting availableLineItems + const resultMap = await settleAllPromises(promiseResultMap); + const glassParts = [...store.getters.order.lineItems.glassParts]; + const availableLineItems = [ + resultMap.rainDefense, + ...resultMap.supportingItems, + ...resultMap.wipers, + ...glassParts, + ]; - // get wiper and rain defense availableLineItems - - // Settle promises and get results - - // get price of supporting, rain defense & wipers, and parts - - // Settle pricing promise and get results + const pricingResults = await baseMixin.methods.dispatchStoreAction( + storeActions.PRICE_ORDER_ITEMS, + availableLineItems, + false + ); // Call the "next" function to complete the transition to this page. next((vm) => { vm.setCmsContent(cmsContent); - vm.availableLineItems = [ - { - partNumber: "001", - Description: "Windshield with Recal", - partType: "Windshield", - Quantity: "1", - BasePartNumber: "001", - Color: "Green", - CanSafeliteRecalibrate: true, - price: 350.22, - }, - { - partNumber: "SBB16", - description: "SAFELITE BEAM BLADE 16", - partType: "FRONT WIPER", - price: 32.64, - }, - { - partNumber: "A DISPOSAL FEE", - partType: "DISPOSAL FEE", - price: 15.0, - }, - { - partNumber: "SBB26", - description: "SAFELITE BEAM BLADE 26", - partType: "FRONT WIPER", - price: 53.04, - }, - { - partNumber: "SBBR12A", - description: "SAFELITE REAR BLADE 12A", - partType: "REAR WIPER", - price: 24.48, - }, - { - partNumber: "RAIN DEFENSE", - description: null, - partType: "RAIN DEFENSE", - price: 35.5, - }, - { - partNumber: "RECAL STATIC", - Description: "Recalibration", - partType: "recalibration", - Quantity: "1", - price: 150.0, - }, - ]; + vm.availableLineItems = pricingResults; vm.isInsuranceSelected = vm.getDefaultIsInsuranceSelectedValue(); }); }, diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index 0f8c73a88..0c75aa788 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -42,6 +42,8 @@ export default { partNumber: singlePart.partNumber, description: singlePart.description, color: singlePart.color, + partType: singlePart.partType, + canSafeliteRecalibrate: singlePart.canSafeliteRecalibrate, requiresRecalibration: singlePart.requiresRecalibration, requiresCapabilityQuestions: singlePart.requiresCapabilityQuestions, recalibrationType: singlePart.recalibrationType, diff --git a/src/store/index.js b/src/store/index.js index 309304714..253b404de 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -342,7 +342,7 @@ export const mutations = { state.order.damage.isRepair = sessionInformation.order.damage.isRepair; state.order.damage.numberOfChips = sessionInformation.order.damage.numberOfChips; - state.order.lineItems.glassParts = sessionInformation.order.lineItems.parts; + state.order.lineItems.glassParts = sessionInformation.order.lineItems.glassParts; state.order.accountNumber = sessionInformation.order.accountNumber; state.order.providerNumber = sessionInformation.order.providerNumber; (state.order.serviceLocation.address = @@ -871,6 +871,49 @@ export const actions = { return response; }, + getWipers(context) { + const carId = context.getters.vehicle.carId; + const serviceZipCode = context.getters.order.serviceLocation.zipCode; + return globalMethods + .callHttpClient({ + method: endpoints.GetWipers.method, + endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`, + }) + .catch((error) => { + // The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow + return []; + }); + }, + + getRainDefense(context) { + return globalMethods.callHttpClient({ + method: endpoints.GetRainDefense.method, + endpoint: endpoints.GetRainDefense.url, + }); + }, + + getSupportingItems(context) { + const glassPartsArray = context.getters.lineItems.glassParts; + if (!glassPartsArray) { + return []; + } + const carId = context.getters.vehicle.carId; + const isRepair = context.getters.damage.isRepair; + const numberOfChips = context.getters.damage.numberOfChips; + const accountNumber = "82791"; //context.getters.order.accountNumber.toString(); + return globalMethods.callHttpClient({ + method: endpoints.GetSupportingItems.method, + endpoint: endpoints.GetSupportingItems.url, + payload: { + carId: carId, + serviceType: isRepair ? "Repair" : "Replace", + //accountNumber: accountNumber, + parts: glassPartsArray, + numberOfRepairChips: isRepair ? numberOfChips : 0, + }, + }); + }, + getCapabilityQuestions(context, { carId, partNumber }) { return globalMethods.callHttpClient({ method: endpoints.GetCapabilityQuestions.method, @@ -984,7 +1027,7 @@ export const actions = { }) .then((response) => { // Flatten location and name properties - response.data.damage?.glassToReplace?.map((glass) => { + response.data.order.damage?.glassToReplace?.map((glass) => { glass.glassLocation = glass.location; glass.glassName = glass.name; delete glass.location; @@ -1311,6 +1354,14 @@ export const actions = { capabilityQuestionAnswers ); }, + // Price order actions + // PLACEHOLDER, WILL CHANGE WHEN PRICING END POINT IS IMPLEMENTED + priceOrderItems(context, availableLineItems) { + availableLineItems.forEach((lineItem) => { + lineItem["price"] = parseFloat((Math.random() * 100).toFixed(2)); + }); + return availableLineItems; + }, // Misc order actions saveServiceLocation(context, serviceLocationInfo) { context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo); @@ -1394,7 +1445,7 @@ function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) { } function convertGlassPieceNamingForApi(glassArray) { - if (!glassArray) return []; + if (!glassArray || glassArray.length === 0) return []; // check if array already converted. (likely when a session has been saved previously and then reloaded) if (glassArray[0].location !== undefined) { diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 063dedd76..d99e42b82 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -662,7 +662,7 @@ describe("Actions", () => { const context = state; globalMethods.callHttpClient.mockImplementation(() => { - return Promise.resolve({ data: { referralNumber: 123 } }); + return Promise.resolve({ data: { referralNumber: 123, order: {} } }); }); const commit = jest.fn(); @@ -675,9 +675,10 @@ describe("Actions", () => { }); // Assert - expect(response.data).toEqual({ referralNumber: 123 }); + expect(response.data).toEqual({ referralNumber: 123, order: {} }); expect(commit).toBeCalledWith(storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION, { referralNumber: 123, + order: {}, }); }); @@ -686,7 +687,7 @@ describe("Actions", () => { const context = state; globalMethods.callHttpClient.mockImplementation(() => { - return Promise.resolve({ data: { eon: "123" } }); + return Promise.resolve({ data: { eon: "123", order: {} } }); }); context.commit = jest.fn(); @@ -709,7 +710,7 @@ describe("Actions", () => { const context = state; globalMethods.callHttpClient.mockImplementation(() => { - return Promise.resolve({ data: { eon: "123" } }); + return Promise.resolve({ data: { eon: "123", order: {} } }); }); context.commit = jest.fn();