diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index 58f22ebe2..262979ed4 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -32,6 +32,7 @@ const errorMessages = { DATE_REQUIRED: "Please select a date", PHONE_REQUIRED: "Please enter your phone number", PHONE_FORMAT: "Phone number must be 10 digits", + PHONE_EXTENSION_FORMAT: "The specified extension is invalid", SMS_CONSENT_REQUIRED_1: "Please select checkbox to receive text messages", SMS_CONSENT_REQUIRED_2: "Please select at least one consent option", YEAR_REQUIRED: "Please select your vehicle year", diff --git a/src/constants/experiments.js b/src/constants/experiments.js index 4fab998af..81444f1e1 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -58,12 +58,17 @@ const experimentSettings = { TIER_ONE: "TierOne", TIER_TWO: "TierTwo", TIER_THREE: "TierThree", + TIER_TWO_DESCRIPTION: "TierTwo_Description", + TIER_THREE_DESCRIPTION: "TierThree_Description", // Consent Management SHOW_CONSENT_MANAGEMENT: "ShowConsentManagement", // YMM BAILOUT_VIN_REQUIRED_VEHICLES: "BailoutVINRequiredVehicles", + + // Promo Banner + SHOW_PROMO_BANNER: "ShowQuotePageRegionalPromoBanner", }; const experimentTriggers = { diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 1857643be..034e0a6ef 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -48,6 +48,7 @@ const queryStrings = { FROM_HERITAGE: "fromheritage", PHONE_NUMBER: "phonenumber", OFFER_QUOTE: "offerquote", + PIA_AUTH_AMOUNT_ADJUST: "piaauthamountadjust", }; export { queryStrings }; diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index 742e1c461..00875bb6f 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -118,6 +118,7 @@ const storeActions = { SAVE_CCTOKEN: "saveCCToken", SAVE_PAYPAL_TOKEN: "savePaypalToken", SAVE_NEXTGEN_SETTLED_AMOUNT: "saveNextGenSettledAmount", + SAVE_AUTHORIZATION_AMOUNT: "saveAuthorizationAmount", SAVE_IS_RECAL_ACK_OPT_IN: "saveIsRecalAckOptIn", SAVE_IS_RECAL_ACKNOWLEDGED_FOR_SCHEDULING: "saveIsRecalAcknowledgedForScheduling", SAVE_IS_OEM_GLASS_SELECTED: "saveIsOemGlassSelected", diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index 8437a395e..d60bca6ea 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -3,6 +3,7 @@ const storeMutations = { UPDATE_CCTOKEN: "updateCCToken", UPDATE_PAYPAL_TOKEN: "updatePaypalToken", UPDATE_NEXTGEN_SETTLED_AMOUNT: "updateNextGenSettledAmount", + UPDATE_AUTHORIZATION_AMOUNT: "updateAuthorizationAmount", // VEHICLE MUTATIONS UPDATE_YEAR: "updateYear", diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index ae6ca6229..a94a4e079 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -114,11 +114,9 @@ - +
+ +
@@ -742,15 +740,6 @@ export default { diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue index 50512bcbf..c21b9164c 100644 --- a/src/layouts/quote/quote.vue +++ b/src/layouts/quote/quote.vue @@ -5,6 +5,14 @@
+
+
+ +
+
@@ -47,8 +55,7 @@ + cmsWidgetName="AfterpayBannerWidget" /> + class="quote-disclaimer text-left text-md-center" /> +
@@ -134,6 +146,7 @@ import textBlock from "@/digital-components/text-block/text-block"; import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal"; import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import afterpayModalBanner from "@/layouts/quote/afterpay-modal-banner/afterpay-modal-banner"; +import promoBanner from "@/layouts/quote/promo-banner/promo-banner"; import recalDisclaimer from "@/layouts/quote/recal-disclaimer/recal-disclaimer.vue"; import saveProgressModalQuestion from "@/fmg-components/save-progress-modal-question/save-progress-modal-question"; import saveProgressPopupQuestion from "@/fmg-components/save-progress-popup-question/save-progress-popup-question"; @@ -684,6 +697,12 @@ export default { showAfterpayBanner() { return !this.isRecalibrationOnOrder || !this.shouldHideRecalibration; }, + showPromoBanner() { + return experimentMixin.methods.hasSettingEqualTo( + experimentSettings.SHOW_PROMO_BANNER, + "true" + ); + }, isRecalPriceRemove() { return ( experimentMixin.methods @@ -1041,6 +1060,7 @@ export default { contentGroupModal, loadingModal, afterpayModalBanner, + promoBanner, promoModalQuestion, recalDisclaimer, saveProgressModalQuestion, @@ -1166,4 +1186,7 @@ export default { :deep(.promo-modal-question a) { @include responsive-font-size-md(0.875rem, 1rem); } +.quote-disclaimer:last-child { + margin-bottom: 1.5rem; +} diff --git a/src/layouts/quote/service-package-question/service-package-question.spec.js b/src/layouts/quote/service-package-question/service-package-question.spec.js index 1d0f78c1a..46b084d02 100644 --- a/src/layouts/quote/service-package-question/service-package-question.spec.js +++ b/src/layouts/quote/service-package-question/service-package-question.spec.js @@ -856,6 +856,52 @@ describe("service-package-question.vue, matching business rules for package disp getExperimentPackageLabelSpy.mockRestore(); }); + it("should use experiment package descriptions when ServicePackageNameTest is active", () => { + const getExperimentPackageDescriptionSpy = jest + .spyOn(servicePackageQuestion.methods, "getExperimentPackageDescription") + .mockImplementation((tierName) => { + const experimentPackageDescriptions = { + [packageNames.TIER_TWO]: "Most popular choice", + [packageNames.TIER_THREE]: "Best value", + }; + + return experimentPackageDescriptions[tierName] ?? null; + }); + + const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; + Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); + mockProps.availableLineItems.push(driverFrontWiperLineItem); + mockProps.availableLineItems.push(passengerFrontWiperLineItem); + const wrapper = setupMocks({ + mountOptionsMockData: { + store: { + getters: { + order: { + damage: { + isRepair: true, + glassToReplace: [], + }, + }, + hasAnyNonWindshieldGlassParts: false, + }, + }, + }, + }); + + expect( + wrapper.vm.servicePackageAnswers[0].additionalButtonData.packageDescription + ).toBeNull(); + expect(wrapper.vm.servicePackageAnswers[1].additionalButtonData.packageDescription).toBe( + "Most popular choice" + ); + expect(wrapper.vm.servicePackageAnswers[2].additionalButtonData.packageDescription).toBe( + "Best value" + ); + expect(wrapper.vm.servicePackageAnswers[1].buttonLabelSubCopy).toBe("MOST POPULAR"); + expect(wrapper.vm.servicePackageAnswers[2].buttonLabelSubCopy).toBe(""); + + getExperimentPackageDescriptionSpy.mockRestore(); + }); it("should use CMS package names when ServicePackageNameTest is not active", () => { const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]); diff --git a/src/layouts/quote/service-package-question/service-package-question.vue b/src/layouts/quote/service-package-question/service-package-question.vue index 4a54ee3f5..905898481 100644 --- a/src/layouts/quote/service-package-question/service-package-question.vue +++ b/src/layouts/quote/service-package-question/service-package-question.vue @@ -159,6 +159,7 @@ export default { ? false : "Special: Save $" + this.getDiscountPrice(answer.Name), isInsuranceSelected: this.isInsuranceSelected, + packageDescription: this.getExperimentPackageDescription(answer.Name), }, })); @@ -265,6 +266,19 @@ export default { ); }, getExperimentPackageLabel(tierName) { + return this.getExperimentPackageSetting(tierName, { + [packageNames.TIER_ONE]: experimentSettings.TIER_ONE, + [packageNames.TIER_TWO]: experimentSettings.TIER_TWO, + [packageNames.TIER_THREE]: experimentSettings.TIER_THREE, + }); + }, + getExperimentPackageDescription(tierName) { + return this.getExperimentPackageSetting(tierName, { + [packageNames.TIER_TWO]: experimentSettings.TIER_TWO_DESCRIPTION, + [packageNames.TIER_THREE]: experimentSettings.TIER_THREE_DESCRIPTION, + }); + }, + getExperimentPackageSetting(tierName, tierSettingKeys) { if ( !experimentMixin.methods.hasSettingEqualTo( experimentSettings.SHOW_SERVICE_PACKAGE_NAME_TEST, @@ -274,13 +288,8 @@ export default { return null; } - const tierSettingKey = { - [packageNames.TIER_ONE]: experimentSettings.TIER_ONE, - [packageNames.TIER_TWO]: experimentSettings.TIER_TWO, - [packageNames.TIER_THREE]: experimentSettings.TIER_THREE, - }[tierName]; - - return tierSettingKey ? experimentMixin.methods.getSettingValue(tierSettingKey) : null; + const settingKey = tierSettingKeys[tierName]; + return settingKey ? experimentMixin.methods.getSettingValue(settingKey) : null; }, getHeaderTextFromCms(cmsWidgetName) { return this.getCmsContent(cmsWidgetName, "HeaderText"); diff --git a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue index 959c7345e..bae95af8f 100644 --- a/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue +++ b/src/layouts/quote/service-package-question/service-package-radio/service-package-radio.vue @@ -2,7 +2,10 @@
@@ -10,6 +13,10 @@

+

+

diff --git a/src/layouts/service-location/shop-question/shop-question-popup.vue b/src/layouts/service-location/shop-question/shop-question-popup.vue index c66f4c79a..385fc27a3 100644 --- a/src/layouts/service-location/shop-question/shop-question-popup.vue +++ b/src/layouts/service-location/shop-question/shop-question-popup.vue @@ -32,10 +32,10 @@ :isRequired="false" :validationRules="''" /> -
+
-
+
{ + if (glass.answerData) { + glass.answerData = {}; + } + }); + }, hasPartQuestions(partsOrQuestions) { return partsOrQuestions?.some((pq) => pq.partQuestions?.length > 0); }, @@ -114,11 +122,12 @@ export default { ); }); // set the answerString to use for answerSelected - if (chosenAns.nextQuestionSequence) { - answerString = `${answeredQuestion.questionNum}|nextQuestion|${chosenAns.nextQuestionSequence}|${chosenAns.answerText}`; - } else { - answerString = `${answeredQuestion.questionNum}|answer|${chosenAns.answerResult}|${chosenAns.answerText}`; - } + answerString = buildQuestionChainAnswerValue({ + questionSequence: answeredQuestion.questionNum, + nextQuestionSequence: chosenAns.nextQuestionSequence, + answerResult: chosenAns.answerResult, + answerText: chosenAns.answerText, + }); // mark this question as answered (question-chain will read this) glass.questions[answeredQuestion.questionNum - 1].answerSelected = @@ -177,6 +186,8 @@ export default { */ const self = vm ?? this; + const isIncomplete = !!answer.incomplete; + const hadSavedAnswer = !!self.questionsData[answer.index]?.answerData?.answerResult; // clear out any preloaded answers self.selectedAnswers = {}; @@ -193,7 +204,6 @@ export default { */ const answeredQuestionText = answeredQuestion.questionText.toUpperCase(); - const answeredQuestionAnswer = answeredQuestion.selectedAnswer.toUpperCase(); const answeredQuestionAnswerText = answeredQuestion.selectedAnswerText.toUpperCase(); const answeredQuestionNum = answeredQuestion.questionNum; @@ -208,8 +218,7 @@ export default { if (answeredQuestionIndex === 0) question.answerSelected = null; if (answeredQuestionNum - 1 === questionIndex) { - // on the right question - question.answerSelected = answeredQuestionAnswer; + question.answerSelected = answeredQuestion.selectedAnswer; } }); } @@ -346,6 +355,27 @@ export default { }); }); + if (isIncomplete) { + // User changed an earlier answer; downstream questions were cleared in the chain + self.questionsData[answer.index].answerData = null; + self.currentGlassIndex = answer.index; + + if (hadSavedAnswer) { + self.questionsData[answer.index].key = + (self.questionsData[answer.index].key ?? + self.questionsData[answer.index].answerKey ?? + answer.index) + Date.now().toString(); + } + + return; + } + + // Force re-render so the updated selection displays when changing a prior answer + self.questionsData[answer.index].key = + (self.questionsData[answer.index].key ?? + self.questionsData[answer.index].answerKey ?? + answer.index) + Date.now().toString(); + // set final answer data for the current answered glass part self.questionsData[answer.index].answerData = { answerResult: answer.answerResult, diff --git a/src/mixins/vehicle-questions-mixin.spec.js b/src/mixins/vehicle-questions-mixin.spec.js index 0fd027258..a557adefa 100644 --- a/src/mixins/vehicle-questions-mixin.spec.js +++ b/src/mixins/vehicle-questions-mixin.spec.js @@ -499,6 +499,88 @@ describe("vehicle-questions-mixin", () => { // Assert expect(wrapper.vm.selectedAnswers).toMatchObject({}); }); + + test("should clear answerData and keep currentGlassIndex when answer is incomplete", () => { + const answer = { + incomplete: true, + answeredQuestions: [ + { + questionText: "Is this the Overland edition?", + selectedAnswer: "1|nextQuestion|5|No", + selectedAnswerText: "No", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.currentGlassIndex = 1; + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [ + { + questionSequence: 1, + questionText: "Is this the Overland edition?", + answers: [], + }, + ], + answerData: { answerResult: "OLD-PART" }, + answerKey: "Windshield-Single", + }, + { + glassLocation: "Driver", + glassName: "Front", + questions: [], + answerData: { answerResult: "OTHER-PART" }, + }, + ]; + + wrapper.vm.handleCompletedQuestionChainAnswers(answer, "", wrapper.vm); + + expect(wrapper.vm.questionsData[0].answerData).toBeNull(); + expect(wrapper.vm.questionsData[1].answerData).toBeNull(); + expect(wrapper.vm.currentGlassIndex).toBe(0); + }); + + test("should not bump key when incomplete answer had no saved answer", () => { + const answer = { + incomplete: true, + answeredQuestions: [ + { + questionText: "Is this the Overland edition?", + selectedAnswer: "1|nextQuestion|2|Yes", + selectedAnswerText: "Yes", + questionNum: 1, + }, + ], + index: 0, + }; + const { wrapper } = setupMocks({}); + + wrapper.vm.questionsData = [ + { + glassLocation: "Windshield", + glassName: "Single", + questions: [ + { + questionSequence: 1, + questionText: "Is this the Overland edition?", + answers: [], + }, + ], + answerData: null, + answerKey: "Windshield-Single", + key: "stable-key", + }, + ]; + + wrapper.vm.handleCompletedQuestionChainAnswers(answer, "", wrapper.vm); + + expect(wrapper.vm.questionsData[0].key).toBe("stable-key"); + }); }); describe("questions in glass parts that are after the answered glass", () => { diff --git a/src/router/methods/route-logic/adyen-return.js b/src/router/methods/route-logic/adyen-return.js index f15168861..9a287b243 100644 --- a/src/router/methods/route-logic/adyen-return.js +++ b/src/router/methods/route-logic/adyen-return.js @@ -2,7 +2,7 @@ import { routeData } from "@/router/constants/routes"; import { createAdyenCheckout, getSessionInfo } from "@/helpers/adyen-helper"; import { mapAdyenToFmgPaymentMethod, generateCcToken } from "@/helpers/adyen-helper"; import baseMixin from "@/mixins/base-mixin.js"; -import { getAmountDue } from "@/helpers/pricing-helper"; +import { getPiaAuthorizationAmount } from "@/helpers/pricing-helper"; import store from "@/store"; import { storeActions } from "@/constants/store-actions"; import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js"; @@ -49,7 +49,7 @@ export async function adyenReturnBeforeEnter(to, from) { // TODO once afterpay info is returned, create cc token and submit order. const paymentMethod = mapAdyenToFmgPaymentMethod(sessionInfo?.paymentMethod); - const amountDue = getAmountDue(store.getters.order.lineItems); + const authorizationAmount = getPiaAuthorizationAmount(store.getters.order.lineItems); const ccToken = generateCcToken(sessionInfo); ccToken.authCode = "831001"; @@ -68,7 +68,13 @@ export async function adyenReturnBeforeEnter(to, from) { await baseMixin.methods.dispatchStoreAction( storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT, - amountDue, + authorizationAmount, + false + ); + + await baseMixin.methods.dispatchStoreAction( + storeActions.SAVE_AUTHORIZATION_AMOUNT, + authorizationAmount, false ); diff --git a/src/store/index.js b/src/store/index.js index d9ca5c6fe..d6410b196 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -133,6 +133,8 @@ const getDefaultState = () => { dateOfLoss: null, damageCause: null, installOemGlass: null, + damageCity: null, + damageState: null, }, lineItems: { glassParts: null, @@ -162,6 +164,7 @@ const getDefaultState = () => { inactivePromos: null, paypalToken: null, nextGenSettledAmount: 0, + authorizationAmount: null, ccToken: { subscriptionId: null, expMonth: null, @@ -488,6 +491,9 @@ export const mutations = { updateNextGenSettledAmount(state, nextGenSettledAmount) { state.order.payment.nextGenSettledAmount = nextGenSettledAmount; }, + updateAuthorizationAmount(state, authorizationAmount) { + state.order.payment.authorizationAmount = authorizationAmount; + }, updateInsuranceVerifiedStatus(state, isVerified) { state.order.payment.insuranceCoverage.isVerified = isVerified; }, @@ -614,6 +620,8 @@ export const mutations = { if (damageDetails) { state.order.damage.dateOfLoss = damageDetails.dateOfLoss; state.order.damage.damageCause = damageDetails.damageCause; + state.order.damage.damageState = damageDetails.damageState; + state.order.damage.damageCity = damageDetails.damageCity; } }, @@ -887,7 +895,8 @@ export const mutations = { sessionInformation.order.damage?.dateOfLoss ); state.order.damage.damageCause = sessionInformation.order.damage?.damageCause; - + state.order.damage.damageState = sessionInformation.order.damage?.damageState; + state.order.damage.damageCity = sessionInformation.order.damage?.damageCity; state.order.damage.partQuestionAnswers = sessionInformation.order.damage.partQuestionAnswers; state.order.damage.moldingQuestionAnswers = @@ -2008,35 +2017,30 @@ export const actions = { const vehicle = context.getters.vehicle; const damage = context.getters.damage; const order = context.state.order; + const payment = context.getters.payment; - const carId = vehicle.carId; - const glassArray = damage.glassToReplace; - const zipCode = order.serviceLocation.zipCode; - const vin = vehicle.vin; - const serviceType = damage.isRepair ? "Repair" : "Install"; - const parentAccountNumber = context.getters.payment.parentAccountNumber; - const referralSeqNumber = order.referralSequenceNumber; - - // create a new array to avoid mutating state - const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray); + const glassArrayForPayload = convertGlassPieceNamingForApi(damage.glassToReplace); const partsOrQuestionsEndpoint = vehicle.vinRequired ? endpoints.GetPartsOrQuestionsV2 : endpoints.GetPartsOrQuestions; + const requestPayload = { + carId: vehicle.carId, + glassPieces: glassArrayForPayload, + zip: order.serviceLocation.zipCode, + vin: vehicle.vin, + serviceType: damage.isRepair ? "Repair" : "Install", + referralSeqNumber: order.referralSequenceNumber, + parentAccountNumber: payment.parentAccountNumber, + billToAccountNumber: payment.billToAccountNumber, + }; + const response = await globalMethods .callHttpClient({ method: partsOrQuestionsEndpoint.method, endpoint: partsOrQuestionsEndpoint.url, - payload: { - carId: carId, - glassPieces: glassArrayForPayload, - zip: zipCode, - vin: vin, - serviceType: serviceType, - referralSeqNumber: referralSeqNumber, - parentAccountNumber: parentAccountNumber, - }, + payload: requestPayload, logApiCall: true, pageNameToLog: pageNameToLog, }) @@ -2072,32 +2076,25 @@ export const actions = { const order = context.state.order; const payment = context.getters.payment; - const carId = vehicle.carId; - const glassArray = damage.glassToReplace; - const resultsArray = damage.partQuestionAnswers; - const zipCode = order.serviceLocation.zipCode; - const vin = vehicle.vin; - const serviceType = order.serviceLocation?.appointmentType; - const referralSeqNumber = order.referralSequenceNumber; - const parentAccountNumber = payment.parentAccountNumber; + const glassArrayForPayload = convertGlassPieceNamingForApi(damage.glassToReplace); + const resultsArrayForPayload = convertResultsForApi(damage.partQuestionAnswers); - // create a new array to avoid mutating state - const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray); - const resultsArrayForPayload = convertResultsForApi(resultsArray); + const requestPayload = { + carId: vehicle.carId, + glassPieces: glassArrayForPayload, + answerResults: resultsArrayForPayload, + zip: order.serviceLocation.zipCode, + vin: vehicle.vin, + serviceType: order.serviceLocation?.appointmentType, + referralSeqNumber: order.referralSequenceNumber, + parentAccountNumber: payment.parentAccountNumber, + billToAccountNumber: payment.billToAccountNumber, + }; const response = await globalMethods.callHttpClient({ method: endpoints.GetParts.method, endpoint: endpoints.GetParts.url, - payload: { - carId: carId, - glassPieces: glassArrayForPayload, - answerResults: resultsArrayForPayload, - zip: zipCode, - vin: vin, - serviceType: serviceType, - referralSeqNumber: referralSeqNumber, - parentAccountNumber: parentAccountNumber, - }, + payload: requestPayload, logApiCall: true, pageNameToLog: pageNameToLog, }); @@ -2860,6 +2857,8 @@ export const actions = { installOemGlass: order.damage.installOemGlass, dateOfLoss: order.damage.dateOfLoss, damageCause: order.damage.damageCause, + damageState: order.damage.damageState, + damageCity: order.damage.damageCity, }, lineItems: { glassParts: lineItems.glassParts, @@ -2893,6 +2892,9 @@ export const actions = { order.payment.piaType == paymentMethods.APPLE_PAY ? true : false, paypalToken: order.payment.paypalToken, nextGenSettledAmount: order.payment.nextGenSettledAmount, + ...(order.payment.authorizationAmount > 0 + ? { authorizationAmount: order.payment.authorizationAmount } + : {}), ccToken: { subscriptionId: order.payment.ccToken.subscriptionId, expMonth: order.payment.ccToken.expMonth, @@ -3047,6 +3049,10 @@ export const actions = { context.commit(storeMutations.UPDATE_NEXTGEN_SETTLED_AMOUNT, nextGenSettledAmount); }, + saveAuthorizationAmount(context, authorizationAmount) { + context.commit(storeMutations.UPDATE_AUTHORIZATION_AMOUNT, authorizationAmount); + }, + savePaypalToken(context, ppToken) { context.commit(storeMutations.UPDATE_PAYPAL_TOKEN, ppToken); }, diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 74cda6c9f..72eaac142 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -920,6 +920,105 @@ describe("Actions", () => { ); }); + it("saveSession action, includes authorizationAmount when PIA was authorized", async () => { + const context = createAuthorizationAmountSaveSessionContext(312.45); + + globalMethods.callHttpClient.mockImplementation(() => { + return Promise.resolve({ data: { referralNumber: 123 } }); + }); + + await actions.saveSession(context, { pageNameToLog: "test" }); + + expect(globalMethods.callHttpClient).toHaveBeenCalledWith( + expect.objectContaining({ + payload: expect.objectContaining({ + order: expect.objectContaining({ + payment: expect.objectContaining({ + authorizationAmount: 312.45, + }), + }), + }), + }) + ); + }); + + it("saveSession action, omits authorizationAmount when PIA was not authorized", async () => { + const context = createAuthorizationAmountSaveSessionContext(null); + + globalMethods.callHttpClient.mockImplementation(() => { + return Promise.resolve({ data: { referralNumber: 123 } }); + }); + globalMethods.callHttpClient.mockClear(); + + await actions.saveSession(context, { pageNameToLog: "test" }); + + const callPayload = globalMethods.callHttpClient.mock.calls[0][0].payload; + expect(callPayload.order.payment.authorizationAmount).toBeUndefined(); + }); + + function createAuthorizationAmountSaveSessionContext(authorizationAmount) { + const context = state; + const damage = { + numberOfChips: "2", + partQuestionAnswers: {}, + moldingQuestionAnswers: {}, + capabilityQuestionAnswers: {}, + }; + + context.getters = { + vehicle: { registration: {} }, + order: { damage }, + damage: {}, + applicationUser: { + lastPageVisited: "test-page", + crmCustomerId: "xxx-xxx-xxx", + savedSessionId: "xxx-xxx-xxx", + }, + }; + context.state = { + order: { + damage, + payment: { + insuranceCoverage: { isVerified: false }, + isInsurance: false, + authorizationAmount, + ccToken: { + subscriptionId: authorizationAmount ? "sub-123" : null, + expMonth: null, + expYear: null, + cardType: null, + billToPostalCode: null, + billToFirstName: null, + billToLastName: null, + referenceNumber: null, + authCode: authorizationAmount ? "831001" : null, + transactionId: null, + transReferenceNumber: null, + lastFour: null, + }, + }, + serviceLocation: {}, + customer: { + emailAddress: "test@safelite.com", + firstName: "John", + lastName: "Doe", + isSmsOptIn: true, + phoneNumber: "1234567890", + address: { + streetAddress: "123 Main St", + streetAddress2: "Apt 1", + city: "Anytown", + state: "OH", + zipCode: "12345", + }, + }, + lineItems: {}, + }, + }; + + return context; + } + it("loadSession action, returns order information, calls mutation", async () => { // Arrange const context = state; diff --git a/src/ux-components/button-main/button-main.spec.js b/src/ux-components/button-main/button-main.spec.js index 76e9afe28..9324726a0 100644 --- a/src/ux-components/button-main/button-main.spec.js +++ b/src/ux-components/button-main/button-main.spec.js @@ -36,48 +36,6 @@ describe("buttonMain.vue", () => { expect(button.attributes()["aria-disabled"]).toEqual("true"); }); - it("Should return loader color", async () => { - // Arrange - const wrapper = shallowMount( - buttonMain, - setupMocks({ - propsData: { - loaderColor: "blue", - loaderEnabled: true, - }, - }) - ); - - // Act - wrapper.vm.clicked(); - await nextTick(); - - // Assert - const loader = wrapper.find("loader-stub"); - expect(loader.attributes("class")).toContain("blue"); - }); - - it("Should return loader position", async () => { - // Arrange - const wrapper = shallowMount( - buttonMain, - setupMocks({ - propsData: { - loaderPosition: "right", - loaderEnabled: true, - }, - }) - ); - - // Act - wrapper.vm.clicked(); - await nextTick(); - - // Assert - const loader = wrapper.find("loader-stub"); - expect(loader.attributes("class")).toContain("right"); - }); - it("Should set 'isLoaderDisplayed' to false when calling 'removeLoader'", async () => { // Arrange const wrapper = shallowMount( diff --git a/src/ux-components/button-main/button-main.vue b/src/ux-components/button-main/button-main.vue index 87eb28841..d91ebf7cd 100644 --- a/src/ux-components/button-main/button-main.vue +++ b/src/ux-components/button-main/button-main.vue @@ -12,7 +12,8 @@ + :loaderColor="loaderColor" + :loaderPosition="loaderPosition" /> @@ -64,6 +65,7 @@ export default {