diff --git a/src/constants/bailoutCode.js b/src/constants/bailoutCode.js index 2cdd8326..26e85ec7 100644 --- a/src/constants/bailoutCode.js +++ b/src/constants/bailoutCode.js @@ -18,7 +18,9 @@ const bailoutCode = Object.freeze({ ApiError: 15, RouterError: 16, CoverageCancelledByUser: 17, - NeedHelp: 18, + FmgPartNotFound: 18, + NeedHelp: 19, + YMMNotFound: 20, }); export default bailoutCode; diff --git a/src/constants/bailoutMessage.js b/src/constants/bailoutMessage.js index b08bb9d9..4c7a73ee 100644 --- a/src/constants/bailoutMessage.js +++ b/src/constants/bailoutMessage.js @@ -101,7 +101,11 @@ const bailoutMessage = Object.freeze({ NeedHelp: () => ({ code: bailoutCode.NeedHelp, message: 'User clicked the Need Help link in the app.' - }) + }), + YMMNotFound: () => ({ + code: bailoutCode.YMMNotFound, + message: 'Vin Required vehicle' + }) }); export default bailoutMessage; diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 59515bd3..e186d76b 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -8,6 +8,7 @@ const LOCATION_BASE_URL = '/location/api/v1/location'; const ORDER_BASE_URL = '/order/api/v1/order'; const PARTS_V1_BASE_URL = '/parts/api/v1/parts'; const PARTS_V2_BASE_URL = '/parts/api/v2/parts'; +const PARTS_V3_BASE_URL = '/parts/api/v3/parts'; const PRICE_BASE_URL = '/price/api/v1/price'; const SCHEDULE_BASE_URL = '/schedule/api/v1/schedule'; const VEHICLE_BASE_URL = '/vehicle/api/v1/vehicle'; @@ -43,7 +44,7 @@ const endpoints = Object.freeze({ method: 'POST' }, GetMobilePremiumFee: { - url: `${PARTS_V1_BASE_URL}/mobile-premium-fee`, + url: `${PARTS_V1_BASE_URL}/mobile-premium-fee`, method: 'GET' }, GetVehicleYears: { @@ -63,15 +64,19 @@ const endpoints = Object.freeze({ method: 'GET' }, GetDamageOptions: { - url: `${PARTS_V1_BASE_URL}/damage-options`, + url: `${PARTS_V1_BASE_URL}/damage-options`, method: 'GET' }, GetPartsOrQuestions: { - url: `${PARTS_V1_BASE_URL}/parts-or-questions`, + url: `${PARTS_V1_BASE_URL}/parts-or-questions`, + method: 'POST' + }, + GetPartsOrQuestionsVinRequired: { + url: `${PARTS_V3_BASE_URL}/parts-or-questions`, method: 'POST' }, GetParts: { - url: `${PARTS_V1_BASE_URL}/parts`, + url: `${PARTS_V1_BASE_URL}/parts`, method: 'POST' }, GetITACPriceOrderItems: { @@ -100,19 +105,19 @@ const endpoints = Object.freeze({ method: 'GET' }, GetCapabilityQuestions: { - url: `${PARTS_V1_BASE_URL}/capability-questions`, + url: `${PARTS_V1_BASE_URL}/capability-questions`, method: 'GET' }, GetPartFromCapabilityAnswer: { - url: `${PARTS_V1_BASE_URL}/part-from-capability-answer`, + url: `${PARTS_V1_BASE_URL}/part-from-capability-answer`, method: 'POST' }, GetWipers: { - url: `${PARTS_V1_BASE_URL}/wipers`, + url: `${PARTS_V1_BASE_URL}/wipers`, method: 'GET' }, GetRainDefense: { - url: `${PARTS_V1_BASE_URL}/rain-repel`, + url: `${PARTS_V1_BASE_URL}/rain-repel`, method: 'GET' }, GetRecalParts: { @@ -124,19 +129,19 @@ const endpoints = Object.freeze({ zipCode, applicationName, referralSequenceNumber - ) => `${PARTS_V1_BASE_URL}/recal-parts/${carId}/${partNumber}/${recalibrationType}/${parentAccountNumber}/${zipCode}/${applicationName}/${referralSequenceNumber}`, + ) => `${PARTS_V1_BASE_URL}/recal-parts/${carId}/${partNumber}/${recalibrationType}/${parentAccountNumber}/${zipCode}/${applicationName}/${referralSequenceNumber}`, method: 'GET' }, GetGlassFees: { - url: `${PARTS_V1_BASE_URL}/glass-fees`, + url: `${PARTS_V1_BASE_URL}/glass-fees`, method: 'GET' }, GetSupportingItems: { - url: `${PARTS_V1_BASE_URL}/supporting-items`, + url: `${PARTS_V1_BASE_URL}/supporting-items`, method: 'POST' }, GetMobileFeePart: { - url: `${PARTS_V2_BASE_URL}/mobile-fee`, + url: `${PARTS_V2_BASE_URL}/mobile-fee`, method: 'GET' }, GetServiceabilityDetails: { diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index 92569c91..52fe0050 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -92,6 +92,7 @@ import { import vinPagesMixin from '@/mixins/vin-pages-mixin'; import { useMainStore } from '@/store/index.js'; import showIssLoadingModal from '@/helpers/loading-modal-helper'; +import bailoutMessage from '@/constants/bailoutMessage'; export default { name: 'address-lookup', @@ -335,10 +336,7 @@ export default { // If a different vehicle is found than the one entered and the selected glass // is not available for that vehicle then navigate back to "vehicle-damage" // display vehicle changed alert on that page. - if ( - this.isCarIdDifferent - && !this.isSelectedGlassAvailableForVehicle - ) { + if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { this.$router.navigate( this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, this.$route, @@ -346,6 +344,13 @@ export default { { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true } ); } else if (matchingCars.length === 1) { + if (this.mainStore.order.vehicle.vinRequired) { + this.mainStore.setBailout(bailoutMessage.YMMNotFound()); + return this.$router.navigate( + this.navigationScenarios.BAILOUT, + this.$route + ); + } await this.navigateForwardWithSingleCarMatch(); } else { this.$router.navigate( diff --git a/src/layouts/address-vehicles/address-vehicles.vue b/src/layouts/address-vehicles/address-vehicles.vue index a04d1216..7b651e7b 100644 --- a/src/layouts/address-vehicles/address-vehicles.vue +++ b/src/layouts/address-vehicles/address-vehicles.vue @@ -256,6 +256,14 @@ export default { false ); + if (this.mainStore.order.vehicle.vinRequired) { + this.mainStore.setBailout(bailoutMessage.YMMNotFound()); + return this.$router.navigate( + this.navigationScenarios.BAILOUT, + this.$route + ); + } + await this.navigateForward(); }, async navigateForward() { diff --git a/src/layouts/bailout-page/bailout-page.vue b/src/layouts/bailout-page/bailout-page.vue index 8e7fa5dd..0e780a5a 100644 --- a/src/layouts/bailout-page/bailout-page.vue +++ b/src/layouts/bailout-page/bailout-page.vue @@ -18,7 +18,7 @@ :contentProperty="subHeaderContentProperty" :stripRteStyle="stripRteStyle" :subContentProperty="subContentProperty" - class="sub-header-content mt-2 mb-5" + class="sub-header-content mb-5" justification="left" />
@@ -159,6 +159,7 @@ export default { defaultSiteHeader: 'SiteSubHeaderWidget', noTpa: 'ContentGroupNoTPAWidget', notSeeingPreferredShop: 'ContentGroupNotSeeingPreferredShop', + ymmNotFound: 'YMMNotFoundWidget', disclaimerText: 'DisclaimerWidget' }, rules: { @@ -172,20 +173,21 @@ export default { computed: { subHeaderCmsWidgetName() { switch (this.bailout.bailoutCode) { - case BailoutCode.TPANotEnabled: - return this.widget.noTpa; - case BailoutCode.DoNotSeeMyShop: return this.widget.notSeeingPreferredShop; - + case BailoutCode.TPANotEnabled: + return this.widget.noTpa; + case BailoutCode.YMMNotFound: + return this.widget.ymmNotFound; default: return this.widget.defaultSiteHeader; } }, subHeaderContentProperty() { switch (this.bailout.bailoutCode) { - case BailoutCode.TPANotEnabled: case BailoutCode.DoNotSeeMyShop: + case BailoutCode.TPANotEnabled: + case BailoutCode.YMMNotFound: return widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT; default: @@ -194,8 +196,9 @@ export default { }, subContentProperty() { switch (this.bailout.bailoutCode) { - case BailoutCode.TPANotEnabled: case BailoutCode.DoNotSeeMyShop: + case BailoutCode.TPANotEnabled: + case BailoutCode.YMMNotFound: return widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT; default: @@ -259,6 +262,10 @@ export default { min-height: 1px; padding-left: .9375rem; padding-right: .9375rem; + + .sub-header-content { + margin-top: 1.25rem; + } } } diff --git a/src/layouts/contact-confirmation/contact-confirmation.vue b/src/layouts/contact-confirmation/contact-confirmation.vue index 2819efd6..42a4a227 100644 --- a/src/layouts/contact-confirmation/contact-confirmation.vue +++ b/src/layouts/contact-confirmation/contact-confirmation.vue @@ -7,7 +7,9 @@
@@ -20,6 +22,8 @@ import siteHeader from '@/iss-components/site-header/site-header.vue'; import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue'; // Supporting files +import BailoutCode from '@/constants/bailoutCode'; +import widgetFields from '@/constants/cms-widget-fields.js'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import issPageValues from '@/router/router-constants/issPage-values.js'; import settleAllPromises from '@/helpers/layout-helper'; @@ -55,12 +59,43 @@ export default { return { mainStore }; }, data() { - const contactConfirmationData = useMainStore().pageData(issPageValues.CONTACT_CONFIRMATION); return { - contactConfirmationModel: contactConfirmationData + bailout: useMainStore().pageData(issPageValues.BAILOUT_PAGE), + contactConfirmationModel: useMainStore().pageData(issPageValues.CONTACT_CONFIRMATION), + widget: { + defaultSiteHeader: 'SiteSubHeaderWidget', + ymmNotFound: 'YMMNotFoundWidget' + }, }; }, - computed: {}, + computed: { + subHeaderCmsWidgetName() { + switch (this.bailout.bailoutCode) { + case BailoutCode.YMMNotFound: + return this.widget.ymmNotFound; + default: + return this.widget.defaultSiteHeader; + } + }, + subHeaderContentProperty() { + switch (this.bailout.bailoutCode) { + case BailoutCode.YMMNotFound: + return widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT; + + default: + return widgetFields.SUB_HEADER_WIDGET.SUB_HEADER_TEXT; + } + }, + subContentProperty() { + switch (this.bailout.bailoutCode) { + case BailoutCode.YMMNotFound: + return widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT; + + default: + return widgetFields.SUB_HEADER_WIDGET.SECONDARY_TEXT; + } + }, + }, methods: {} }; diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index aeb58dcb..d70c7b39 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -76,6 +76,7 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import settleAllPromises from '@/helpers/layout-helper'; import { useMainStore } from '@/store'; +import bailoutMessage from '@/constants/bailoutMessage'; import errorMessages from '@/constants/error-messages'; import { required } from '@/helpers/validation-rules'; import { defineRule, Form } from 'vee-validate'; @@ -303,6 +304,14 @@ export default { } }); + if (this.mainStore.order.vehicle.vinRequired) { + this.mainStore.setBailout(bailoutMessage.YMMNotFound()); + return this.$router.navigate( + this.navigationScenarios.BAILOUT, + this.$route + ); + } + return this.navigateForward(); }, async navigateForward() { diff --git a/src/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue b/src/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue index fa5868aa..6a17f75c 100644 --- a/src/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue +++ b/src/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue @@ -65,6 +65,13 @@ export default { const homeAddressIndex = answers.findIndex(answer => answer.Name === vinLookupMethodSelections.HOMEADDRESS); answers.splice(homeAddressIndex, 1); } + + const isVinRequired = useMainStore().order.vehicle.vinRequired; + if (isVinRequired) { + const vinIndex = answers.findIndex(answer => answer.Name === vinLookupMethodSelections.NOVIN); + answers.splice(vinIndex, 1); + } + this.answersFromCms = answers; } }, diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index 9057e864..de36af0f 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -176,6 +176,16 @@ export default { this.$refs.siteFooter.enableForwardAction(); showIssLoadingModal(true); + this.mainStore.order.vehicle.vinRequired = true; // have to find out where this is reset + this.needToLookupVehicle = true; // have to find out where this is reset + if (this.mainStore.order.vehicle.vinRequired) { + this.mainStore.setBailout(bailoutMessage.YMMNotFound()); + return this.$router.navigate( + this.navigationScenarios.BAILOUT, + this.$route + ); + } + if (this.needToLookupVehicle) { try { const vehicleLookupResponse = await this.lookupVehicleByVin(this.vin); @@ -262,6 +272,26 @@ export default { return; } + if (this.mainStore.order.vehicle.vinRequired) { + const partsOrQuestionsResponse = await this.getPartsOrQuestionsVinRequired() + .then(async (response) => { + await this.navigateForward( + partsOrQuestionsResponse.data.partsOrQuestions, + this + ); + return response; + }) + .catch((e) => { + this.mainStore.setBailout(bailoutMessage.HeavyTruckVehicle(this.vehicleFromLookup.carId)); + this.$router.navigate( + this.navigationScenarios.BAILOUT, + this.$route + ); + throw e; + }); + + return; + } const partsOrQuestionsResponse = await this.getPartsOrQuestions(); // Comes from vehicleQuestionsMixin.navigateForward() diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index 956ef0af..2330dde9 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -68,7 +68,7 @@ export default { const store = useMainStore(); const issConfig = store.issConfig; const currentPageName = this.getPageNameByQueryString(); - //await this.validateSession(); + // await this.validateSession(); const submittedOrder = store.getSubmittedOrder(); const hasSubmittedOrder = store.hasSubmittedOrder(); @@ -98,7 +98,7 @@ export default { const store = useMainStore(); const issConfig = store.issConfig; const currentPageName = this.getPageNameByQueryString(); - //await this.validateSession(); + // await this.validateSession(); const submittedOrder = store.getSubmittedOrder(); const hasSubmittedOrder = store.hasSubmittedOrder(); @@ -246,6 +246,18 @@ export default { payload.vehicleStyle = ""; } + if (isDefined(order.vehicle.carId)) { + payload.vehicleCarId = order.vehicle.carId; + } else { + payload.vehicleCarId = ""; + } + + if (isDefined(order.vehicle.vinRequired)) { + payload.vehicleIsVinRequired = order.vehicle.vinRequired; + } else { + payload.vehicleIsVinRequired = ""; + } + // Glass pieces const glass = order.damage.glassToReplace ?? []; if (glass.length === 0) { @@ -257,7 +269,7 @@ export default { payload.glassToReplace = glassString; } - //EON + // EON if (order.eon) { payload.eon = order.eon; } else { @@ -555,7 +567,6 @@ export default { }, async initSession() { - regenerateDeviceId(); regenerateUserId(); diff --git a/src/mixins/vehicle-questions-mixin.js b/src/mixins/vehicle-questions-mixin.js index b4bdad07..54331ae6 100644 --- a/src/mixins/vehicle-questions-mixin.js +++ b/src/mixins/vehicle-questions-mixin.js @@ -355,6 +355,9 @@ export default { async getPartsOrQuestions() { return useMainStore().getPartsOrQuestions(); }, + async getPartsOrQuestionsVinRequired() { + return useMainStore().getPartsOrQuestionsVinRequired(); + }, // Can't use `this` because navigateForward is also called from vin-pages-mixin async navigateForward(partsOrQuestions, vm) { diff --git a/src/store/index.js b/src/store/index.js index dee920e0..c734f307 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -4,13 +4,13 @@ import bailoutCode from '@/constants/bailoutCode'; import coverageStatuses from '@/constants/coverage-statuses'; import coverageType from '@/constants/coverage-type'; import damageLocationsSelected from '@/constants/damage-locations-selected'; -import endorsementOptions from '@/constants/endorsement-options'; import endpoints from '@/constants/endpoints'; import { experimentSettings, experimentTriggers, experimentUniverses } from '@/constants/experiments'; import partNumberStrings from '@/constants/part-number-strings'; import partTypeStrings from '@/constants/part-type-strings'; import { paymentMethods } from '@/constants/payment-method-constants'; import { AppointmentTypeStrings } from '@/constants/schedule-constants'; +import submitType from '@/constants/submit-type'; import webStorageConstants from '@/constants/web-storage-constants'; import globalMethods from '@/global-methods'; import { getSessionKeyValue, getUserIdValue, deleteISSCookie, getDeviceIdValue } from '@/helpers/cookie-helper'; @@ -27,7 +27,6 @@ import { getRecalPartNumbers, getTopLevelGlassPartsWithRecal, getHasRecalibratio import { getDateForSavedSessionTimeout } from '@/helpers/session-helper'; import { isMobileDevice } from '@/helpers/useragent-helper'; import issPageValues from '@/router/router-constants/issPage-values'; -import CoverageStatuses from '@/constants/coverage-statuses'; import { getNonFalseValuesOfPropertyInArrayOfObjects, sortArrayOfObjectsByPropertyValue } from '@/helpers/object-helper'; const storeId = 'main'; @@ -85,7 +84,10 @@ export const getDefaultState = () => ({ lastName: null }, isBigTruck: null, - canSafeliteService: null + canSafeliteService: null, + skipVINLookup: null, + skipPartQuestions: null, + vinRequired: null }, damage: { isRepair: null, @@ -762,7 +764,7 @@ export const useMainStore = defineStore({ this.updateDeductible(r.data); return r; } catch (e) { - this.updateCoverageStatus(CoverageStatuses.PENDING); + this.updateCoverageStatus(coverageStatuses.PENDING); } }, @@ -808,9 +810,7 @@ export const useMainStore = defineStore({ }, // PartsOrQuestions API Actions - async getPartsOrQuestions() { - this.resetPartsAndDependencies(); - + getPartsOrQuestionsPayload() { const { vehicle } = this; const { damage } = this; const { order } = this; @@ -822,17 +822,22 @@ export const useMainStore = defineStore({ // create a new array to avoid mutating state const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray); + return { + carId, + glassPieces: glassArrayForPayload, + zip: zipCode, + vin, + oemEndorsementFlag: this.hasOemEndorsement + }; + }, + async getPartsOrQuestions() { + this.resetPartsAndDependencies(); + const payload = this.getPartsOrQuestionsPayload(); const response = await globalMethods.callHttpClient({ method: endpoints.GetPartsOrQuestions.method, endpoint: endpoints.GetPartsOrQuestions.url, - payload: { - carId, - glassPieces: glassArrayForPayload, - zip: zipCode, - vin, - oemEndorsementFlag: this.hasOemEndorsement - } + payload: payload }); // Flatten location and name properties @@ -840,7 +845,21 @@ export const useMainStore = defineStore({ return response; }, + async getPartsOrQuestionsVinRequired() { + this.resetPartsAndDependencies(); + const payload = this.getPartsOrQuestionsPayload(); + const response = await globalMethods.callHttpClient({ + method: endpoints.GetPartsOrQuestionsVinRequired.method, + endpoint: endpoints.GetPartsOrQuestionsVinRequired.url, + payload: payload + }); + + // Flatten location and name properties + response.data.partsOrQuestions = convertGlassPieceNamingFromApi(response.data.partsOrQuestions); + + return response; + }, async getParts() { const { vehicle } = this.order; const { damage } = this.order; @@ -2081,6 +2100,9 @@ export const useMainStore = defineStore({ this.order.vehicle.imageColor = vehicle.imageVifColor; this.order.vehicle.isBigTruck = vehicle.isBigTruck; this.order.vehicle.canSafeliteService = vehicle.canSafeliteService; + this.order.vehicle.skipVINLookup = vehicle.skipVINLookup; + this.order.vehicle.skipPartQuestions = vehicle.skipPartQuestions; + this.order.vehicle.vinRequired = vehicle.vinRequired; this.updateSupportingItems(null); this.updateVaps(null); @@ -2215,6 +2237,9 @@ export const useMainStore = defineStore({ this.order.vehicle.registration.lastName = null; this.order.vehicle.isBigTruck = null; this.order.vehicle.canSafeliteService = null; + this.order.vehicle.skipVINLookup = null; + this.order.vehicle.skipPartQuestions = null; + this.order.vehicle.vinRequired = null; if (this.isBailout && this.bailoutCode === bailoutCode.HeavyTruckVehicle) { this.resetBailout(); @@ -3158,7 +3183,7 @@ export const useMainStore = defineStore({ return JSON.parse(window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER)); }, - async createSubmittedOrder(submitType) { + async createSubmittedOrder(pSubmitType) { if (this.hasSubmittedOrder()) { return; } @@ -3169,16 +3194,27 @@ export const useMainStore = defineStore({ submittedOrder.isUnverified = this.isUnverified; submittedOrder.isVerified = this.isVerified; - submittedOrder.submitType = submitType; + submittedOrder.submitType = pSubmitType; submittedOrder.payment.isPayInAdvance = this.isPayInAdvance; submittedOrder.hasRecalibrationPart = hasRecalibrationPart; // set to sessionStorage window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); + let persistedBailout = null; + if (pSubmitType === submitType.BAILOUT) { + persistedBailout = this.pageData(issPageValues.BAILOUT_PAGE); + } // clear vuex this.resetState(); + if (persistedBailout) { + this.updatePageData({ + page: issPageValues.BAILOUT_PAGE, + data: persistedBailout + }); + } + // delete cookie deleteISSCookie();