diff --git a/src/App.vue b/src/App.vue index 36c4b58a3..e0bce4693 100644 --- a/src/App.vue +++ b/src/App.vue @@ -87,9 +87,22 @@ window.onerror = (msg, url, line, col, error) => { return suppressErrorAlert; }; +function isThirdPartyUnhandledRejection(reason) { + const stack = reason instanceof Error ? reason.stack : ""; + if (typeof stack !== "string") { + return false; + } + + return stack.includes("chrome-extension://") || stack.includes("quantummetric.com"); +} + // Log Promise rejections that are never handled (.catch / await try/catch), e.g. fire-and-forget async. window.addEventListener("unhandledrejection", (event) => { const reason = event.reason; + if (isThirdPartyUnhandledRejection(reason)) { + return; + } + const message = reason instanceof Error ? reason.message : String(reason); global.$logger.logError(`unhandledrejection: ${message}`, { stack: reason instanceof Error ? reason.stack : undefined, diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 9a105cc0f..4196cbf19 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -56,8 +56,8 @@ const endpoints = { url: "/parts/api/v1/parts/parts-or-questions", method: "POST", }, - GetPartsOrQuestionsV3: { - url: "/parts/api/v3/parts/parts-or-questions", + GetPartsOrQuestionsV2: { + url: "/parts/api/v2/parts/parts-or-questions", method: "POST", }, GetParts: { diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js index c9f78cb7b..7e136fefa 100644 --- a/src/constants/store-actions.js +++ b/src/constants/store-actions.js @@ -133,8 +133,6 @@ const storeActions = { UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError", GET_VALID_IDEMPOTENCY_KEY: "getValidIdempotencyKey", CORRECT_IDEMPOTENCY_KEY_EXPIRY: "correctIdempotencyKeyExpiry", - - SAVE_BAILOUT_CODE: "saveBailoutCode", }; export { storeActions }; diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js index d0efaf4e6..71816b499 100644 --- a/src/constants/store-mutations.js +++ b/src/constants/store-mutations.js @@ -118,9 +118,6 @@ const storeMutations = { UPDATE_EXPERIMENTS: "updateExperiments", UPDATE_TRIGGERED_SITE_ENTRY: "updateTriggeredSiteEntry", - // BAILOUT MUTATIONS - UPDATE_BAILOUT_CODE: "updateBailoutCode", - // EXTERNAL_PARAMETER MUTATIONS UPDATE_IS_EXTERNAL_PARAMETER: "updateIsExternalParameter", UPDATE_EXTERNAL_PARAMETER_YEAR: "updateExternalParameterYear", diff --git a/src/digital-components/textbox-question/textbox-question.spec.js b/src/digital-components/textbox-question/textbox-question.spec.js index be33230c2..d83eb6509 100644 --- a/src/digital-components/textbox-question/textbox-question.spec.js +++ b/src/digital-components/textbox-question/textbox-question.spec.js @@ -13,6 +13,22 @@ const mockMixin = { const maska = jest.fn(); describe("textboxQuestion.vue", () => { + it("Should coerce non-string modelValue to empty string for v-model.trim", async () => { + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + modelValue: null, + }, + mixins: [mockMixin], + }); + + expect(wrapper.vm.value).toBe(""); + }); + it("Should render a text input", async () => { // Arrange const wrapper = shallowMount(textboxQuestion, { diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 2f1780eea..c6cdad971 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -25,7 +25,7 @@ 0 ? modelValue : ""; - break; - } + const modelValue = coerceTextboxValue(propsClone.modelValue); + const initialValue = modelValue; const fieldOptions = { type: "text", @@ -168,6 +171,8 @@ export default { initialValue: initialValue, }; + let isImageProcessing = ref(false); + const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField( inputId, props.validationRules, @@ -228,18 +233,25 @@ export default { }, value: { get: function () { - return this.modelValue; + return coerceTextboxValue(this.modelValue); }, set: function (newValue) { this.$emit("update:modelValue", newValue); }, }, + effectiveMask() { + return this.mask ?? ""; + }, }, mounted() { this.$emit("textboxQuestionEvent.inputIdAssigned", this.inputId); }, watch: { async value(newValue) { + if (typeof this.handleChange !== "function") { + return; + } + const result = await validate(newValue, this.validationRules); // do a test validation check, without triggering full validation if (result.valid) { this.handleChange(newValue); // trigger full validation on this field only diff --git a/src/fmg-components/content-group-modal/content-group-modal.vue b/src/fmg-components/content-group-modal/content-group-modal.vue index e4a5241c4..12b4acf32 100644 --- a/src/fmg-components/content-group-modal/content-group-modal.vue +++ b/src/fmg-components/content-group-modal/content-group-modal.vue @@ -14,6 +14,7 @@ class="my-4 caption modal-sub-body" v-if="ModalSubBodyText" v-html="ModalSubBodyText">

+

@@ -58,6 +59,9 @@ export default { ModalCloseButtonText() { return this.getCmsContent(this.cmsWidgetName, "FooterText"); }, + ModalFooter2Text() { + return this.getCmsContent(this.cmsWidgetName, "FooterText2"); + }, }, methods: { openModal() { diff --git a/src/helpers/heritage-integration/navigation-helper.js b/src/helpers/heritage-integration/navigation-helper.js index a2b4452d5..029fb1f08 100644 --- a/src/helpers/heritage-integration/navigation-helper.js +++ b/src/helpers/heritage-integration/navigation-helper.js @@ -65,6 +65,9 @@ export async function skipVinLookup() { if (store.getters.damage.isRepair) { return true; } + if (store.getters.vehicle.vinRequired) { + return false; + } const isVinOptionalVehicle = store.getters.order.vehicle.make ? await store.dispatch(storeActions.IS_VIN_OPTIONAL_VEHICLE) : false; diff --git a/src/helpers/heritage-integration/navigation-helper.spec.js b/src/helpers/heritage-integration/navigation-helper.spec.js index 752c98fdc..ab1b9d6d7 100644 --- a/src/helpers/heritage-integration/navigation-helper.spec.js +++ b/src/helpers/heritage-integration/navigation-helper.spec.js @@ -11,6 +11,7 @@ import { damageLocationsSelected as glassLocations } from "@/constants/damage-lo import store from "@/store"; import router from "@/router"; +import { skipVinLookup } from "@/helpers/heritage-integration/navigation-helper"; const getPageToRouteExistingOrderTo = navigationHelper.getPageToRouteExistingOrderTo; const navigateToHeritageFunnel = navigationHelper.navigateToHeritageFunnel; @@ -147,6 +148,20 @@ describe("navigateToHeritageFunnel", () => { }); }); +describe("skipVinLookup", () => { + afterEach(() => { + store.commit(storeMutations.UPDATE_VIN_REQUIRED, false); + store.commit(storeMutations.UPDATE_IS_REPAIR, false); + }); + + test("returns false when vehicle vin is required", async () => { + store.commit(storeMutations.UPDATE_VIN_REQUIRED, true); + store.commit(storeMutations.UPDATE_IS_REPAIR, false); + + await expect(skipVinLookup()).resolves.toBe(false); + }); +}); + /** * `arePagePrerequisitesValidObject` is an object where the keys are fmgPageValue names and the values are booleans that indicate * whether arePagePrerequisitesValid is true or false diff --git a/src/layouts/bailout/bailout.vue b/src/layouts/bailout/bailout.vue index 12cca1b92..b1f9722db 100644 --- a/src/layouts/bailout/bailout.vue +++ b/src/layouts/bailout/bailout.vue @@ -159,7 +159,7 @@ export default { methods: { getBailoutCodeFromStore() { - return store.getters.applicationUser.bailoutCode; + return store.getters.bailoutCode; }, getFirstNameFromStore() { return store.getters.order.customer.firstName; @@ -233,7 +233,6 @@ export default { this.navigationScenarios.CLICKED_FORWARD, this.pageName, { - bailoutCode: this.bailoutCode, submit: true, } ); @@ -244,7 +243,7 @@ export default { } }, arePagePrerequisitesValid() { - return this.getBailoutCodeFromStore() !== null; + return this.getBailoutCodeFromStore() != null; }, }, diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index c9d9d572c..eec23bfee 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -4,7 +4,6 @@ cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" :overrideImageSrc="clientLogoImageSrc" /> -
diff --git a/src/layouts/duplicate-check/duplicate-check.vue b/src/layouts/duplicate-check/duplicate-check.vue index 40f0a8c0d..a5d624de8 100644 --- a/src/layouts/duplicate-check/duplicate-check.vue +++ b/src/layouts/duplicate-check/duplicate-check.vue @@ -4,7 +4,6 @@ cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" :overrideImageSrc="clientLogoImageSrc" /> -
diff --git a/src/layouts/endorsements/endorsements.vue b/src/layouts/endorsements/endorsements.vue index 7aa027dec..4e16fb05b 100644 --- a/src/layouts/endorsements/endorsements.vue +++ b/src/layouts/endorsements/endorsements.vue @@ -4,7 +4,6 @@ cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" :overrideImageSrc="clientLogoImageSrc" /> -
diff --git a/src/layouts/mobile-details/mobile-details.vue b/src/layouts/mobile-details/mobile-details.vue index cb98386e6..1dcd75a36 100644 --- a/src/layouts/mobile-details/mobile-details.vue +++ b/src/layouts/mobile-details/mobile-details.vue @@ -34,7 +34,7 @@ class="keys-message" /> -
diff --git a/src/layouts/policy-info-submitted/policy-info-submitted.vue b/src/layouts/policy-info-submitted/policy-info-submitted.vue index 5afec595d..d3b4d22c0 100644 --- a/src/layouts/policy-info-submitted/policy-info-submitted.vue +++ b/src/layouts/policy-info-submitted/policy-info-submitted.vue @@ -4,7 +4,6 @@ cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" :overrideImageSrc="clientLogoImageSrc" /> -
diff --git a/src/layouts/policy-info/policy-info.vue b/src/layouts/policy-info/policy-info.vue index 57e32f2f7..242202143 100644 --- a/src/layouts/policy-info/policy-info.vue +++ b/src/layouts/policy-info/policy-info.vue @@ -4,7 +4,6 @@ cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" :overrideImageSrc="clientLogoImageSrc" /> -
diff --git a/src/layouts/policy-vehicle/policy-vehicle.vue b/src/layouts/policy-vehicle/policy-vehicle.vue index 768169127..e03a9e766 100644 --- a/src/layouts/policy-vehicle/policy-vehicle.vue +++ b/src/layouts/policy-vehicle/policy-vehicle.vue @@ -4,7 +4,6 @@ cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" :overrideImageSrc="clientLogoImageSrc" /> -
diff --git a/src/layouts/recalibration-info/recalibration-info.vue b/src/layouts/recalibration-info/recalibration-info.vue index 032348457..a592d70ae 100644 --- a/src/layouts/recalibration-info/recalibration-info.vue +++ b/src/layouts/recalibration-info/recalibration-info.vue @@ -4,7 +4,6 @@ cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" :overrideImageSrc="clientLogoImageSrc" /> -
diff --git a/src/layouts/scheduling/date-picker/date-picker.vue b/src/layouts/scheduling/date-picker/date-picker.vue index 3ade2058e..5e7caf089 100644 --- a/src/layouts/scheduling/date-picker/date-picker.vue +++ b/src/layouts/scheduling/date-picker/date-picker.vue @@ -10,22 +10,42 @@ class="date-picker__nav-icon date-picker__nav-icon--flipped" alt="" /> -
- +
+ +