import { createStore } from "vuex"; import { endpoints } from "@/constants/endpoints.js"; import { storeMutations } from "@/constants/store-mutations"; import { getDateForSavedSessionTimeout } from "@/helpers/heritage-integration/session-helper"; import createPersistedState from "vuex-persistedstate"; import globalMethods from "@/global-methods"; import { storeActions } from "@/constants/store-actions"; import { applicationConfig } from "@/constants/application-config"; import { experimentTriggers } from "@/constants/experiments"; import { damageLocationsSelected } from "@/constants/damage-locations-selected"; import { singleWindshieldCarIds } from "@/constants/single-windshield-carids"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js"; import { deepEqual } from "@/helpers/object-helper"; import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE, RouteCodeFlags, } from "@/constants/schedule-constants"; import { getQuerystringParameter } from "@/helpers/querystring-helper"; import { deepClone } from "@/helpers/object-helper"; import { queryStrings } from "@/constants/query-strings"; import { partTypeStrings } from "@/constants/part-type-strings"; import { convertDateStringToDate, militaryToTwelveHourTime, } from "@/layouts/schedule/helpers/schedule-helper"; import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helper"; import { paymentMethods } from "@/constants/payment-method-constants"; import { getPromoCodeWithoutBundleIdentifier, removeCurrentlyActivePromoCodesFromInactivePromos, } from "@/helpers/promotions-helper"; import { getDateDifferenceInDays } from "@/helpers/date-helper"; import sharedMutations from "./vuex-shared-mutations/vuexSharedMutations"; import { coverageStatus, coverageStatusValue, coverageStatusEnum, coverageType, coverageTypeValue, coverageTypeEnum, } from "@/constants/insurance"; import { containsRecalParts, getTopLevelPartsWithRecal, isRecalPartOrHasChildRecalPart, } from "@/helpers/recal-helper"; import { externalParameterStatus } from "@/constants/external-parameters"; import { experimentSettings } from "@/constants/experiments"; import experimentMixin from "@/mixins/experiment-mixin.js"; // Export State const getDefaultState = () => { return { order: { vehicle: { year: null, make: null, model: null, style: null, carId: null, category: null, vin: null, imageUrl: null, imageVifNumber: null, imageColor: null, registration: { licensePlate: null, }, }, serviceLocation: { address: null, address2: null, city: null, state: null, zipCode: null, zipCodeCtu: null, appointmentType: null, isVehicleProtected: null, provider: { providerNumber: null, address: { streetAddress: null, city: null, state: null, zipCode: null, zipCodeCtu: null, }, }, techNotes: null, }, customer: { firstName: null, lastName: null, emailAddress: null, phoneNumber: null, isSmsOptIn: null, }, damage: { isRepair: null, numberOfChips: null, glassToReplace: null, partQuestionAnswers: null, moldingQuestionAnswers: null, capabilityQuestionAnswers: null, dateOfLoss: null, damageCause: null, }, lineItems: { glassParts: null, supportingItems: null, vaps: null, serverData: null, promos: null, }, payment: { isInsurance: null, insuranceCoverage: { isVerified: null, coverageStatus: null, coverageSubStatus: null, coverageType: null, coverageVerificationType: null, }, parentAccountNumber: 0, billToAccountNumber: null, isPia: null, piaType: null, inactivePromos: null, paypalToken: null, nextGenSettledAmount: 0, ccToken: { subscriptionId: null, expMonth: null, expYear: null, cardType: null, billToPostalCode: null, billToFirstName: null, billToLastName: null, referenceNumber: null, authCode: null, transactionId: null, transReferenceNumber: null, lastFour: null, }, }, policy: { currentDeductible: 0, policyNumber: null, isItac: false, additionalAuthFlag: null, isNoComp: false, insuranceCompanyName: null, }, schedule: { date: null, startTime: null, endTime: null, routeCode: null, jobMaxMinutes: null, jobMinMinutes: null, }, referralNumber: null, referralSequenceNumber: null, referralDate: null, referralCorrelationId: null, eon: null, workOrderNumber: null, workOrderId: null, customerPortalLoginToken: null, lockToken: null, settledTenderAmount: 0, isRecalAckOptIn: false, }, applicationUser: { eventBus: [], pageData: {}, savedSessionTimeout: getDateForSavedSessionTimeout(), saveSessionPromise: null, savedSessionId: null, crmCustomerId: null, lastPageVisited: null, experiments: [], triggeredSiteEntry: false, affiliateCookies: [], loggingOption: false, }, }; }; export const state = getDefaultState(); export const externalParameterState = getExternalParameterDefaultState(); // Export Mutations export const mutations = { // VEHICLE MUTATIONS updateYear(state, year) { state.order.vehicle.year = year; }, updateMake(state, make) { state.order.vehicle.make = make; }, updateModel(state, model) { state.order.vehicle.model = model; }, updateStyle(state, style) { state.order.vehicle.style = style; }, updateCarId(state, carId) { state.order.vehicle.carId = carId; }, updateVehicleCategory(state, category) { state.order.vehicle.category = category; }, updateVehicleImageUrl(state, imageUrl) { state.order.vehicle.imageUrl = imageUrl; }, updateVehicleImageVifNumber(state, imageVifNumber) { state.order.vehicle.imageVifNumber = imageVifNumber; }, updateVehicleImageColor(state, imageColor) { state.order.vehicle.imageColor = imageColor; }, updateVehicleVin(state, vin) { state.order.vehicle.vin = vin; }, updateIsRepair(state, isRepair) { state.order.damage.isRepair = isRepair; }, updateNumberOfChips(state, numberOfChips) { state.order.damage.numberOfChips = numberOfChips; }, updateGlassToReplace(state, glassToReplace) { state.order.damage.glassToReplace = glassToReplace; }, updatePartQuestionAnswers(state, answersArray) { state.order.damage.partQuestionAnswers = answersArray; }, updateMoldingQuestionAnswers(state, answersArray) { state.order.damage.moldingQuestionAnswers = answersArray; }, updateCapabilityQuestionAnswers(state, answersArray) { state.order.damage.capabilityQuestionAnswers = answersArray; }, updateGlassParts(state, partsData) { state.order.lineItems.glassParts = partsData; }, updateVaps(state, partsData) { state.order.lineItems.vaps = partsData; }, updateSupportingItems(state, partsData) { state.order.lineItems.supportingItems = partsData; }, updateLineItemsServerData(state, serverData) { state.order.lineItems.serverData = serverData; }, updateInactivePromos(state, inactivePromos) { state.order.payment.inactivePromos = inactivePromos; }, updatePromos(state, promos) { state.order.lineItems.promos = promos; }, updatePageData(state, pageData) { state.applicationUser.pageData[pageData.page] = pageData.data; }, updateReferralCorrelationId(state, referralCorrelationId) { state.order.referralCorrelationId = referralCorrelationId; }, updateReferralNumber(state, referralNumber) { state.order.referralNumber = referralNumber; }, updateReferralSequenceNumber(state, referralSequenceNumber) { state.order.referralSequenceNumber = referralSequenceNumber; }, updateReferralDate(state, referralDate) { state.order.referralDate = referralDate; }, updateParentAcctNumber(state, parentAcctNumber) { state.order.payment.parentAccountNumber = parentAcctNumber; }, updateBillToAcctNumber(state, billToAcctNumber) { state.order.payment.billToAccountNumber = billToAcctNumber; }, updateEON(state, eon) { state.order.eon = eon; }, updateIsInsurance(state, isInsurance) { state.order.payment.isInsurance = isInsurance; }, updateIsPia(state, isPia) { state.order.payment.isPia = isPia; }, updatePiaType(state, piaType) { state.order.payment.piaType = piaType; }, updateWorkOrderNumber(state, workOrderNumber) { state.order.workOrderNumber = workOrderNumber; }, updateWorkOrderId(state, workOrderId) { state.order.workOrderId = workOrderId; }, updateCustomerPortalLoginToken(state, customerPortalLoginToken) { state.order.customerPortalLoginToken = customerPortalLoginToken; }, updateLockToken(state, lockToken) { state.order.lockToken = lockToken; }, updateSettledTenderAmount(state, settledTenderAmount) { state.order.settledTenderAmount = settledTenderAmount; }, updateIsRecalAckOptIn(state, isRecalAckOptIn) { state.order.isRecalAckOptIn = isRecalAckOptIn; }, updateCCToken(state, ccToken) { state.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; state.order.payment.ccToken.expMonth = ccToken.expMonth; state.order.payment.ccToken.expYear = ccToken.expYear; state.order.payment.ccToken.cardType = ccToken.cardType; state.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; state.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; state.order.payment.ccToken.billToLastName = ccToken.billToLastName; state.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; state.order.payment.ccToken.authCode = ccToken.authCode; state.order.payment.ccToken.transactionId = ccToken.transactionId; state.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; state.order.payment.ccToken.lastFour = ccToken.lastFour; }, updatePaypalToken(state, ppToken) { state.order.payment.paypalToken = ppToken; }, updateNextGenSettledAmount(state, nextGenSettledAmount) { state.order.payment.nextGenSettledAmount = nextGenSettledAmount; }, updateInsuranceVerifiedStatus(state, isVerified) { state.order.payment.insuranceCoverage.isVerified = isVerified; }, updateCustomerEmailAddress(state, customerEmailAddress) { state.order.customer.emailAddress = customerEmailAddress; }, updateVehicle(state, vehicleInfo) { state.order.vehicle.year = vehicleInfo.year; state.order.vehicle.make = vehicleInfo.make; state.order.vehicle.model = vehicleInfo.model; state.order.vehicle.style = vehicleInfo.style; state.order.vehicle.carId = vehicleInfo.carId; state.order.vehicle.category = vehicleInfo.category; state.order.vehicle.vin = vehicleInfo.vin; state.order.vehicle.imageUrl = vehicleInfo.imageUrl; state.order.vehicle.imageVifNumber = vehicleInfo.imageVifNumber; state.order.vehicle.imageColor = vehicleInfo.imageVifColor; }, updateRegistration(state, registrationInfo) { state.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate; }, updateServiceZip(state, serviceZipInfo) { state.order.serviceLocation.state = serviceZipInfo.state; state.order.serviceLocation.zipCode = serviceZipInfo.zipCode; state.order.serviceLocation.zipCodeCtu = serviceZipInfo.zipCodeCtu; }, updateServiceLocation(state, serviceLocationInfo) { state.order.serviceLocation.address = serviceLocationInfo.address; state.order.serviceLocation.address2 = serviceLocationInfo.address2; state.order.serviceLocation.city = serviceLocationInfo.city; state.order.serviceLocation.state = serviceLocationInfo.state; state.order.serviceLocation.zipCode = serviceLocationInfo.zipCode; state.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu; state.order.serviceLocation.appointmentType = serviceLocationInfo.appointmentType; state.order.serviceLocation.isVehicleProtected = serviceLocationInfo.isVehicleProtected; state.order.serviceLocation.provider = { providerNumber: serviceLocationInfo.provider?.providerNumber, address: { streetAddress: serviceLocationInfo.provider?.address?.streetAddress, city: serviceLocationInfo.provider?.address?.city, state: serviceLocationInfo.provider?.address?.state, zipCode: serviceLocationInfo.provider?.address?.zipCode, zipCodeCtu: serviceLocationInfo.provider?.address?.zipCodeCtu, }, }; }, updateServiceLocationTechNotes(state, techNotes) { state.order.serviceLocation.techNotes = techNotes; }, updateSchedule(state, scheduleInfo) { if (scheduleInfo) { state.order.schedule.date = scheduleInfo.date; state.order.schedule.startTime = scheduleInfo.startTime; state.order.schedule.endTime = scheduleInfo.endTime; state.order.schedule.routeCode = scheduleInfo.routeCode; state.order.schedule.jobMaxMinutes = scheduleInfo.jobMaxMinutes; state.order.schedule.jobMinMinutes = scheduleInfo.jobMinMinutes; } }, updateCustomerDetails(state, customerDetails) { if (customerDetails) { state.order.customer.firstName = customerDetails.firstName; state.order.customer.lastName = customerDetails.lastName; state.order.customer.emailAddress = customerDetails.emailAddress; state.order.customer.phoneNumber = customerDetails.phoneNumber; state.order.customer.isSmsOptIn = customerDetails.isSmsOptIn; } }, // applicationUser MUTATIONS updateSaveSessionPromise(state, saveSessionPromise) { state.applicationUser.saveSessionPromise = saveSessionPromise; }, updateSavedSessionId(state, savedSessionId) { state.applicationUser.savedSessionId = savedSessionId; }, updateCrmCustomerId(state, crmCustomerId) { state.applicationUser.crmCustomerId = crmCustomerId; }, updateLastPageVisited(state, lastPageVisited) { state.applicationUser.lastPageVisited = lastPageVisited; }, updateLoggingOption(state, loggingOption) { state.applicationUser.loggingOption = loggingOption; }, // EVENT BUS MUTATIONS addEventToBus(state, event) { state.applicationUser.eventBus.push(event); }, removeEventFromBus(state, eventData) { const matchedEvent = state.applicationUser.eventBus.find( ({ category, subCategory }) => category === eventData.category && subCategory === eventData.subCategory ); const itemIndex = state.applicationUser.eventBus.indexOf(matchedEvent); // If the item exists, remove it. if (itemIndex > -1) { state.applicationUser.eventBus.splice(itemIndex, 1); } }, //ExternalParameter MUTATIONS updateIsExternalParameter(state, isExternalParameter) { externalParameterState.isExternalParameter = isExternalParameter; saveExternalParameterState(externalParameterState); }, updateExternalParameterYear(state, year) { externalParameterState.vehicle.year = year; saveExternalParameterState(externalParameterState); }, updateExternalParameterMake(state, make) { externalParameterState.vehicle.make = make; saveExternalParameterState(externalParameterState); }, updateExternalParameterModel(state, model) { externalParameterState.vehicle.model = model; saveExternalParameterState(externalParameterState); }, updateExternalParameterStyle(state, style) { externalParameterState.vehicle.style = style; saveExternalParameterState(externalParameterState); }, updateExternalParameterIsRepair(state, isRepair) { externalParameterState.vehicleDamage.isRepair = isRepair; saveExternalParameterState(externalParameterState); }, updateExternalParameterNumberOfChips(state, numberOfChips) { externalParameterState.vehicleDamage.numberOfChips = numberOfChips; saveExternalParameterState(externalParameterState); }, updateExternalParameterDamageType(state, damageType) { externalParameterState.vehicleDamage.damageType = damageType; saveExternalParameterState(externalParameterState); }, updateExternalParameterZipCode(state, zipCode) { externalParameterState.serviceZip.zipCode = zipCode; saveExternalParameterState(externalParameterState); }, updateExternalParameterEmailAddress(state, emailAddress) { externalParameterState.serviceZip.emailAddress = emailAddress; saveExternalParameterState(externalParameterState); }, updateExternalParameterIsInsurance(state, isInsurance) { externalParameterState.quote.isInsurance = isInsurance; saveExternalParameterState(externalParameterState); }, updateExternalParameterVinSelection(state, vinSelection) { externalParameterState.estimate.vinSelection = vinSelection; saveExternalParameterState(externalParameterState); }, updateExternalParameterServicePackage(state, servicePackage) { externalParameterState.quote.servicePackage = servicePackage; saveExternalParameterState(externalParameterState); }, //RESET ExternalParameter MUTATIONS resetExternalParameterVehicleState(state) { externalParameterState.vehicle.year = null; externalParameterState.vehicle.make = null; externalParameterState.vehicle.model = null; externalParameterState.vehicle.style = null; saveExternalParameterState(externalParameterState); }, resetExternalParameterDamageState(state) { externalParameterState.vehicleDamage.isRepair = null; externalParameterState.vehicleDamage.numberOfChips = null; externalParameterState.vehicleDamage.damageType = null; saveExternalParameterState(externalParameterState); }, resetExternalParameterEstimateState(state) { externalParameterState.estimate.vinSelection = null; saveExternalParameterState(externalParameterState); }, resetExternalParameterServiceZipState(state) { externalParameterState.serviceZip.zipCode = null; externalParameterState.serviceZip.emailAddress = null; saveExternalParameterState(externalParameterState); }, resetExternalParameterQuoteState(state) { externalParameterState.quote.servicePackage = null; saveExternalParameterState(externalParameterState); }, resetIsExternalParameter(state) { externalParameterState.isExternalParameter = externalParameterStatus.INACTIVE; saveExternalParameterState(externalParameterState); }, // RESET DEPENDENCY MUTATIONS resetVehicleState(state) { state.order.vehicle.year = null; state.order.vehicle.make = null; state.order.vehicle.model = null; state.order.vehicle.style = null; state.order.vehicle.carId = null; state.order.vehicle.category = null; state.order.vehicle.vin = null; state.order.vehicle.imageUrl = null; state.order.vehicle.imageVifNumber = null; state.order.vehicle.imageColor = null; }, resetDamageState(state) { state.order.damage.isRepair = null; state.order.damage.numberOfChips = null; state.order.damage.glassToReplace = null; }, resetRegistrationState(state) { state.order.vehicle.registration.licensePlate = null; }, resetGlassPartsState(state) { state.order.lineItems.glassParts = null; state.order.damage.partQuestionAnswers = null; state.order.damage.moldingQuestionAnswers = null; state.order.damage.capabilityQuestionAnswers = null; state.applicationUser.pageData[fmgPageValues.PART_QUESTIONS] = null; state.applicationUser.pageData[fmgPageValues.VEHICLE_PARTS] = null; state.applicationUser.pageData[fmgPageValues.MOLDING_QUESTIONS] = null; state.applicationUser.pageData[fmgPageValues.CAPABILITY_QUESTIONS] = null; }, resetSchedule(state) { state.order.schedule.date = null; state.order.schedule.startTime = null; state.order.schedule.endTime = null; state.order.schedule.routeCode = null; state.order.schedule.jobMaxMinutes = null; state.order.schedule.jobMinMinutes = null; //premium appointment fee used on schedule page also needs reset when schedule is reset const supportingItems = state.order.lineItems.supportingItems; const premiumAppointmentFeeIndex = supportingItems?.findIndex( (item) => item.partType == PREMIUM_FEE_PART_TYPE ); if (premiumAppointmentFeeIndex >= 0) { supportingItems.splice(premiumAppointmentFeeIndex, 1); state.order.lineItems.supportingItems = supportingItems; } }, resetState(state) { Object.assign(state, getDefaultState()); }, resetSaveSessionPromise(state) { state.applicationUser.saveSessionPromise = null; }, resetServiceLocationAppointmentType(state) { state.order.serviceLocation.appointmentType = null; }, resetServiceLocationProvider(state) { state.order.serviceLocation.provider = { providerNumber: null, address: { streetAddress: null, city: null, state: null, zipCode: null, zipCodeCtu: null, }, }; }, resetServiceLocationMobileAddress(state) { state.order.serviceLocation.address = null; state.order.serviceLocation.address2 = null; state.order.serviceLocation.city = null; state.order.serviceLocation.state = null; state.order.serviceLocation.isVehicleProtected = null; }, resetPaymentMethodChoice(state) { state.order.payment.isPia = null; state.order.payment.piaType = null; }, // Misc Mutations updateStateWithOrderInformation(state, sessionInformation) { state.order.referralNumber = sessionInformation.order.referralNumber; state.order.referralSequenceNumber = sessionInformation.order.referralSequenceNumber; state.order.referralDate = sessionInformation.order.referralDate; state.order.referralCorrelationId = sessionInformation.order.referralCorrelationId; state.order.eon = sessionInformation.order.eon; state.order.customerPortalLoginToken = sessionInformation.order.CustomerPortalLoginToken; state.order.isRecalAckOptIn = sessionInformation.order.isRecalAckOptIn; if (state.order.vehicle.vin !== sessionInformation.order.vehicle?.vin) { state.applicationUser.pageData[fmgPageValues.PART_QUESTIONS] = null; state.applicationUser.pageData[fmgPageValues.VEHICLE_PARTS] = null; state.applicationUser.pageData[fmgPageValues.MOLDING_QUESTIONS] = null; state.applicationUser.pageData[fmgPageValues.CAPABILITY_QUESTIONS] = null; } state.order.vehicle = Object.assign(state.order.vehicle, { year: sessionInformation.order.vehicle?.year, make: sessionInformation.order.vehicle?.make, model: sessionInformation.order.vehicle?.model, style: sessionInformation.order.vehicle?.style, vin: sessionInformation.order.vehicle?.vin, carId: sessionInformation.order.vehicle?.carId, category: sessionInformation.order.vehicle?.category, imageUrl: sessionInformation.order.vehicle?.imageUrl, imageVifNumber: sessionInformation.order.vehicle?.imageVifNumber, imageColor: sessionInformation.order.vehicle?.imageVifColor, }); state.order.damage.glassToReplace = sessionInformation.order.damage.glassToReplace; state.order.damage.isRepair = sessionInformation.order.damage.isRepair; state.order.damage.numberOfChips = sessionInformation.order.damage.numberOfChips; state.order.damage.dateOfLoss = sessionInformation.order.damage?.dateOfLoss; state.order.damage.damageCause = sessionInformation.order.damage?.damageCause; state.order.damage.partQuestionAnswers = sessionInformation.order.damage.partQuestionAnswers; state.order.damage.moldingQuestionAnswers = sessionInformation.order.damage.moldingQuestionAnswers; state.order.damage.capabilityQuestionAnswers = sessionInformation.order.damage.capabilityQuestionAnswers; state.order.lineItems.glassParts = sessionInformation.order.lineItems.glassParts; state.order.lineItems.supportingItems = sessionInformation.order.lineItems.supportingItems; state.order.lineItems.vaps = sessionInformation.order.lineItems.vaps ?? []; state.order.lineItems.promos = sessionInformation.order.lineItems.promos; state.order.lineItems.serverData = sessionInformation.order.lineItems.serverData; state.order.payment.parentAccountNumber = sessionInformation.order.payment.parentAccountNumber; state.order.payment.billToAccountNumber = sessionInformation.order.payment.billToAccountNumber; state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos; state.order.serviceLocation.address = sessionInformation.order.serviceLocation.streetAddress; state.order.serviceLocation.address2 = sessionInformation.order.serviceLocation.streetAddress2; state.order.serviceLocation.city = sessionInformation.order.serviceLocation.city; state.order.serviceLocation.state = sessionInformation.order.serviceLocation.state; state.order.serviceLocation.zipCode = sessionInformation.order.serviceLocation.zipCode; state.order.serviceLocation.zipCodeCtu = sessionInformation.order.serviceLocation.zipCodeCtu; state.order.serviceLocation.appointmentType = sessionInformation.order.serviceLocation.appointmentType; state.order.serviceLocation.isVehicleProtected = sessionInformation.order.serviceLocation.isVehicleProtected; state.order.serviceLocation.provider.providerNumber = sessionInformation.order.serviceLocation.provider?.providerNumber; state.order.serviceLocation.provider.address.streetAddress = sessionInformation.order.serviceLocation.provider?.address?.streetAddress; state.order.serviceLocation.provider.address.city = sessionInformation.order.serviceLocation.provider?.address?.city; state.order.serviceLocation.provider.address.state = sessionInformation.order.serviceLocation.provider?.address?.state; state.order.serviceLocation.provider.address.zipCode = sessionInformation.order.serviceLocation.provider?.address?.zipCode; state.order.serviceLocation.provider.address.zipCodeCtu = sessionInformation.order.serviceLocation.provider?.address?.zipCodeCtu; state.order.serviceLocation.techNotes = sessionInformation.order.serviceLocation.techNotes; // if we're loading a session and we do not have a provider number yet, then set isInsurance to null so that // a service package is not selected by default on the quote page. if ( !sessionInformation.order.payment.isInsurance && !sessionInformation.order.serviceLocation.provider?.providerNumber ) { state.order.payment.isInsurance = null; } else { state.order.payment.isInsurance = sessionInformation.order.payment.isInsurance; } state.order.payment.insuranceCoverage.isVerified = coverageStatusValue(sessionInformation?.order.insuranceCoverage.coverageStatus) === coverageStatus.VERIFIED ? true : false; state.order.payment.insuranceCoverage.coverageStatus = coverageStatusValue( sessionInformation?.order.insuranceCoverage.coverageStatus ); state.order.payment.insuranceCoverage.coverageSubStatus = sessionInformation?.order.insuranceCoverage.coverageSubStatus; state.order.payment.insuranceCoverage.coverageType = coverageTypeValue( sessionInformation?.order.insuranceCoverage.coverageType ); state.order.payment.insuranceCoverage.coverageVerificationType = sessionInformation?.order.insuranceCoverage.coverageVerificationType; state.order.customer.emailAddress = sessionInformation.order.customer.emailAddress; state.order.customer.firstName = sessionInformation.order.customer.firstName; state.order.customer.lastName = sessionInformation.order.customer.lastName; state.order.customer.phoneNumber = sessionInformation.order.customer.homePhone; state.order.customer.isSmsOptIn = sessionInformation.order.customer.isSmsOptIn; state.applicationUser.experiments = sessionInformation.applicationUser.experiments; state.applicationUser.crmCustomerId = sessionInformation.applicationUser.crmCustomerId; state.applicationUser.pageData = sessionInformation.applicationUser.pageData; state.applicationUser.lastPage = sessionInformation.applicationUser.lastPage; if (sessionInformation.applicationUser.savedSessionId) { state.applicationUser.savedSessionId = sessionInformation.applicationUser.savedSessionId; } state.order.schedule.date = sessionInformation.order.schedule?.date; state.order.schedule.startTime = sessionInformation.order.schedule?.startTime; state.order.schedule.endTime = sessionInformation.order.schedule?.endTime; state.order.schedule.routeCode = sessionInformation.order.schedule?.routeCode; state.order.schedule.jobMaxMinutes = sessionInformation.order.schedule?.jobMaxMinutes; state.order.schedule.jobMinMinutes = sessionInformation.order.schedule?.jobMinMinutes; state.order.policy.currentDeductible = sessionInformation.order.policy?.currentDeductible; state.order.policy.additionalAuthFlag = sessionInformation.order.policy?.additionalAuthFlag; state.order.policy.isItac = coverageTypeValue(sessionInformation?.order.insuranceCoverage.coverageType) === coverageType.ITAC ? true : false; state.order.policy.policyNumber = sessionInformation.order.policy?.policyNumber; state.order.policy.insuranceCompanyName = sessionInformation.order.policy?.insuranceCompanyName; state.order.policy.isNoComp = coverageTypeValue(sessionInformation?.order.insuranceCoverage.coverageType) === coverageType.NOCOMP ? true : false; sessionInformation.order.policy?.noComprehensive; }, updateExperiments(state, experiments) { state.applicationUser.experiments = experiments; }, updateTriggeredSiteEntry(state, wasSiteEntryTriggered) { state.applicationUser.triggeredSiteEntry = wasSiteEntryTriggered; }, updateAffiliateCookies(state, affiliateCookies) { state.applicationUser.affiliateCookies = affiliateCookies; }, }; // Export Getters export const getters = { vehicle: (state) => state.order.vehicle, eventBusItem: (state) => (eventCategory, eventSubCategory) => { const matchedEvent = state.applicationUser.eventBus.find( ({ category, subCategory }) => category === eventCategory && subCategory === eventSubCategory ); return matchedEvent !== undefined ? matchedEvent.eventValue : undefined; }, eventBus: (state) => state.applicationUser.eventBus, damage: (state) => state.order.damage, hasExactlyOneChip: (state) => { return state.order.damage?.numberOfChips === 1; }, hasAnyNonWindshieldGlassParts: (state) => { const nonWindshieldItems = state.order.damage.glassToReplace?.filter( (glassToReplace) => glassToReplace.glassLocation != "Windshield" ); return !!nonWindshieldItems?.length; }, coverageIsVerified: (state) => { let order; if (window.sessionStorage.getItem("submittedOrder") !== null) { order = JSON.parse(window.sessionStorage.getItem("submittedOrder")); } else { order = state.order; } if ( order.payment?.insuranceCoverage?.isVerified && order.policy?.currentDeductible != 9999 && order.policy?.currentDeductible != 7777 ) { return true; } return false; }, isMobileAppointment: (state) => { return state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE; }, isDropOffAppointment: (state) => { return state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF; }, isOvernightDropOffAppointment: (state) => { return state.order.schedule.routeCode?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF); }, isRecalibrationOnOrder: (state) => { return getHasRecalibrationPart(state); }, isRecalibrationOnSubmittedOrder: (state) => { if (window.sessionStorage.getItem("submittedOrder") !== null) { return getHasRecalibrationPart({ order: JSON.parse(window.sessionStorage.getItem("submittedOrder")), }); } return false; }, shouldHideRecalibration: (state) => { var order; if (window.sessionStorage.getItem("submittedOrder") !== null) { order = JSON.parse(window.sessionStorage.getItem("submittedOrder")); } else { order = state.order; } if (order.payment.isInsurance) { return false; } return ( experimentMixin.methods .getSettingValue(experimentSettings.RECAL_PRICE_REMOVE) ?.toLowerCase() === "true" && getters.isRecalibrationOnOrder(state) ); }, areRearWipersOnOrder: (state) => { return !!state.order.lineItems.vaps?.some( (vap) => vap.partType.toUpperCase() === partTypeStrings.REAR_WIPER.toUpperCase() ); }, scheduleDisplayText: (state) => { const dateModel = convertDateStringToDate(state.order.schedule.date); const readableDate = dateModel?.toLocaleDateString("en-us", { weekday: "long", month: "long", day: "numeric", year: "numeric", }); const readableStartTime = militaryToTwelveHourTime(state.order.schedule.startTime); const readableEndTime = militaryToTwelveHourTime(state.order.schedule.endTime); const readableDuration = getDisplayTextForDurationLength( state.order.schedule.jobMinMinutes, state.order.schedule.jobMaxMinutes ); return { date: readableDate, startTime: readableStartTime, endTime: readableEndTime, duration: readableDuration, }; }, lineItems: (state) => state.order.lineItems, pageData: (state) => (page) => { return state.applicationUser.pageData[page]; }, applicationUser: (state) => state.applicationUser, order: (state) => state.order, payment: (state) => state.order.payment, policy: (state) => state.order.policy, experimentOrder: (state) => { return { funnelVehicleYear: state.order.vehicle.year, funnelVehicleMake: state.order.vehicle.make, funnelVehicleModel: state.order.vehicle.model, funnelVehicleStyle: state.order.vehicle.style, funnelIsRepair: state.order.damage.isRepair, funnelNumberOfChips: state.order.damage.numberOfChips, funnelCarId: state.order.vehicle.carId, funnelServiceCity: state.order.serviceLocation.city, funnelServiceState: state.order.serviceLocation.state, funnelServiceZipCode: state.order.serviceLocation.zipCode, funnelServiceZipCodeCtu: state.order.serviceLocation.zipCodeCtu, funnelProviderNumber: state.order.serviceLocation.provider.providerNumber, funnelParentAccountNumber: state.order.payment.parentAccountNumber, funnelReferralType: state.order.payment.isInsurance ? "INSURANCE" : "CASH QUOTE", funnelIsCoverageVerified: state.order.payment.insuranceCoverage.isVerified, funnelHasRecalibrationPart: getHasRecalibrationPart(state), funnelSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1, funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects( state.order.damage.glassToReplace, "glassLocation" ).includes(damageLocationsSelected.WINDSHIELD), funnelSelectedBackGlass: getNonFalseValuesOfPropertyInArrayOfObjects( state.order.damage.glassToReplace, "glassLocation" ).includes(damageLocationsSelected.REAR), funnelSelectedDriverSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects( state.order.damage.glassToReplace, "glassLocation" ).includes(damageLocationsSelected.DRIVER), funnelSelectedPassengerSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects( state.order.damage.glassToReplace, "glassLocation" ).includes(damageLocationsSelected.PASSENGER), funnelOrderPartNumbers: [ ...getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.glassParts, "partNumber" ), ...getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.supportingItems, "partNumber" ), ...getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.vaps, "partNumber" ), ], funnelOrderPartTypes: [ ...getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.glassParts, "recalibrationType" ), ], }; }, experimentSettings: (state) => state.applicationUser.experiments .filter((x) => !!x.isActive) .map((x) => x.settings) .reduce((r, c) => Object.assign(r, c), {}) ?? {}, isVerifiedAndDeductibleZeroConfirmed: (state) => { // used in CMS on /payment-method in Header Sub Text, for FunnelSubHeaderWidget on cart pages if ( state.order.policy.currentDeductible === 0 && getters.coverageIsVerified(state) && !state.order.policy.isNoComp ) { return true; } return false; }, isItacOrNoComp: (state) => { // used in CMS on /payment-method in Header Sub Text, for FunnelSubHeaderWidget on cart pages if (state.order.policy.isNoComp || state.order.policy.isItac) { return true; } else { return false; } }, requiresVerifiedRedirecting: (state) => { return state.order?.referralNumber?.length === 6; }, externalParameterState: (state) => externalParameterState, externalParameterVehicle: (state) => externalParameterState?.vehicle, externalParameterDamage: (state) => externalParameterState?.vehicleDamage, externalParameterQuote: (state) => externalParameterState?.quote, externalParameterServiceZip: (state) => externalParameterState?.serviceZip, externalParameterEstimate: (state) => externalParameterState?.estimate, isExternalParameter: (state) => externalParameterState?.isExternalParameter, }; function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) { return (array ?? []).map((x) => x[propertyName]).filter((x) => x); } function getTimeSlotsAdditionalEventData( provisionalTriggers, zipCode, firstAvailableAppointmentDateString, shopAppointmentType ) { var numberOfDays = null; if (firstAvailableAppointmentDateString) numberOfDays = getDateDifferenceInDays( new Date().toISOString().split("T")[0], firstAvailableAppointmentDateString ); if (shopAppointmentType) return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ShopAppointmentType:${shopAppointmentType},ProvisionalTriggers:${provisionalTriggers.join( "," )}`; else return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ProvisionalTriggers:${provisionalTriggers.join( "," )}`; } // Export Actions export const actions = { // Vehicle API Actions getVehicleYears(context, { pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.GetVehicleYears.method, endpoint: endpoints.GetVehicleYears.url, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }); }, lookupVehicleByYmms(context, { payload: { year, make, model, style }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.LookupVehicleByYmms.method, endpoint: `${endpoints.LookupVehicleByYmms.url}/${year}/${make}/${model}/${style}`, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }); }, lookupVehicleByVin(context, { payload: { vin }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.LookupVehicleByVin.method, endpoint: endpoints.LookupVehicleByVin.url, payload: { vin: vin, // EX "1J4GW58S4XC541166" logEnabled: context.getters.applicationUser.loggingOption, }, logApiCall: true, pageNameToLog: pageNameToLog, }); }, lookupVinByPlate(context, { payload: { licensePlate, licenseState }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.LookupVinByPlate.method, endpoint: endpoints.LookupVinByPlate.url, payload: { licensePlate: licensePlate, licenseState: licenseState, }, logApiCall: true, pageNameToLog: pageNameToLog, }); }, lookupVinByAddress( context, { payload: { licenseLastName, licenseStreetAddress, licenseZip, licenseState }, pageNameToLog, } ) { return globalMethods.callHttpClient({ method: endpoints.LookupVinByAddress.method, endpoint: endpoints.LookupVinByAddress.url, payload: { licenseLastName: licenseLastName, licenseStreetAddress: licenseStreetAddress, licenseZip: licenseZip, licenseState: licenseState, }, logApiCall: true, pageNameToLog: pageNameToLog, }); }, lookupVinByImage(context, { payload, pageNameToLog }) { const image = payload; return new Promise((resolve, reject) => { let reader = new FileReader(); reader.onload = (e) => { resolve(reader.result); }; reader.readAsDataURL(image); }).then((result) => { const components = result.split(","); const contentType = image.type; const imageBase64 = components[1]; const data = { imageData: imageBase64, contentType: contentType, fileName: image.name, }; return globalMethods.callHttpClient({ method: endpoints.LookupVinByImage.method, endpoint: endpoints.LookupVinByImage.url, payload: data, logApiCall: true, pageNameToLog: pageNameToLog, }); }); }, isVinByAddressPermissible(context, { payload: { zip }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.IsVinByAddressPermissible.method, endpoint: `${endpoints.IsVinByAddressPermissible.url}?zipcode=${zip}`, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getVehicleMakes(context, { payload: { year }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.GetVehicleMakes.method, endpoint: `${endpoints.GetVehicleMakes.url}/${year}`, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getVehicleModels(context, { payload: { year, make }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.GetVehicleModels.method, endpoint: `${endpoints.GetVehicleModels.url}/${year}/${make}`, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getVehicleStyles(context, { payload: { year, make, model }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.GetVehicleStyles.method, endpoint: `${endpoints.GetVehicleStyles.url}/${year}/${make}/${model}`, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getVehicle(context, { payload: { year, make, model, style }, pageNameToLog }) { return globalMethods .callHttpClient({ methods: endpoints.GetVehicle.method, endpoint: `${endpoints.GetVehicle.url}/${year}/${make}/${model}/${style}`, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }) .then((response) => { return response; }); }, getDamageOptions(context, { payload: { carId }, pageNameToLog }) { return globalMethods.callHttpClient({ methods: endpoints.GetDamageOptions.method, endpoint: `${endpoints.GetDamageOptions.url}/${carId}`, payload: {}, additionalSuccessEventDataHandler: (response) => "QueryStringZip: " + getQuerystringParameter(queryStrings.ZIP_CODE), logApiCall: true, pageNameToLog: pageNameToLog, }); }, validateZip(context, { payload: { zip }, pageNameToLog }) { const damageType = context.getters.damage.isRepair ? "Repair" : "Replace"; return globalMethods.callHttpClient({ methods: endpoints.ValidateZip.method, endpoint: `${endpoints.ValidateZip.url}/${zip}/${damageType}`, logApiCall: true, pageNameToLog: pageNameToLog, }); }, // Dependency Actions resetVehicleStateAndDependencies(context) { context.commit(storeMutations.RESET_VEHICLE_STATE); context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); }, resetDamageAndDependencies(context) { context.commit(storeMutations.RESET_DAMAGE_STATE); context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); context.commit(storeMutations.UPDATE_VAPS, null); }, resetRegistrationAndDependencies(context) { context.commit(storeMutations.RESET_REGISTRATION_STATE); context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); }, resetPartsAndDependencies(context) { context.commit(storeMutations.RESET_GLASS_PARTS_STATE); context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null); context.commit(storeMutations.UPDATE_VAPS, null); context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES); }, resetServiceLocationAndDependencies(context) { context.commit(storeMutations.RESET_SERVICE_LOCATION_APPOINTMENT_TYPE); context.commit(storeMutations.RESET_SERVICE_LOCATION_PROVIDER); context.commit(storeMutations.RESET_SCHEDULE); context.commit(storeMutations.RESET_PAYMENT_METHOD_CHOICE); }, resetState(context) { context.commit(storeMutations.RESET_STATE); }, resetSaveSessionPromise(context) { context.commit(storeMutations.RESET_SAVE_SESSION_PROMISE); }, getPageData(context, { pageName }) { return globalMethods.callHttpClient({ method: endpoints.GetPageData.method, endpoint: endpoints.GetPageData.url( applicationConfig.APPLICATION_ABBREVIATION, pageName ), payload: {}, logApiCall: true, pageNameToLog: pageName, }); }, // Analytics Actions logExperimentExposure( context, { payload: { userId, sessionKey, pageName, experiment }, pageNameToLog } ) { return globalMethods.callHttpClient({ method: endpoints.LogExperimentExposureIfAssigned.method, endpoint: endpoints.LogExperimentExposureIfAssigned.url, payload: { experimentForLogging: { userId: userId, experimentUniverseId: experiment.universeId, experimentUniverseName: experiment.universeName, experimentTestId: experiment.testId, experimentTestName: experiment.testName, experimentVariationId: experiment.variationId, experimentVariationName: experiment.variationName, enabled: experiment.isActive, isExposed: experiment.isExposed, userPartitionNumber: experiment.userPartitionNumber, assignmentId: experiment.assignmentId, sessionKey: sessionKey, pageName: pageName, }, }, logApiCall: true, pageNameToLog: pageNameToLog, }); }, // Location API Actions getAlertReasonsByCtu(context, { payload: { ctu }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.GetAlertReasons.method, endpoint: `${endpoints.GetAlertReasons.url}/${ctu}`, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }); }, // Misc Actions updateStoreWithSaveSessionResponse( context, { referralNumber, referralSequenceNumber, referralDate, referralCorrelationId, eon, parentAccountNumber, savedSessionId, crmCustomerId, workOrderNumber, workOrderId, customerPortalLoginToken, lockToken, settledTenderAmount, billToAccountNumber, } ) { context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber); context.commit(storeMutations.UPDATE_REFERRAL_SEQUENCE_NUMBER, referralSequenceNumber); context.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate); context.commit(storeMutations.UPDATE_REFERRAL_CORRELATION_ID, referralCorrelationId); context.commit(storeMutations.UPDATE_EON, eon); context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber); context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId); context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId); context.commit(storeMutations.WORK_ORDER_NUMBER, workOrderNumber); context.commit(storeMutations.WORK_ORDER_ID, workOrderId); context.commit(storeMutations.LOCK_TOKEN, lockToken); context.commit(storeMutations.Customer_Portal_Login_Token, customerPortalLoginToken); context.commit(storeMutations.UPDATE_SETTLED_TENDER_AMOUNT, settledTenderAmount); context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber); }, logPageView( context, { userId, sessionKey, pageName, sessionId, action, event, shouldUseSessionId, experimentsForUser, referralSequenceNumber, parentAccountNumber, } ) { if (!pageName) { return; } var payload = { userId: userId, sessionKey: sessionKey, sessionId: sessionId, pageName: pageName, applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME, action: action, event: event, shouldUseSessionId: shouldUseSessionId, experimentsForUser: experimentsForUser, referralSequenceNumber: referralSequenceNumber, parentAccountNumber: parentAccountNumber ?? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, }; return globalMethods .callHttpClient({ method: endpoints.LogPageView.method, endpoint: endpoints.LogPageView.url, payload: payload, logApiCall: false, }) .then((response) => { return response; }); }, logCustomEvent( context, { userId, sessionKey, pageName, sessionId, category, action, label, value, shouldUseSessionId, experimentsForUser, referralSequenceNumber, parentAccountNumber, } ) { if (!pageName) { return; } var payload = { userId: userId, sessionKey: sessionKey, sessionId: sessionId, pageName: pageName, applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME, category: category, action: action, label: label, value: value, shouldUseSessionId: shouldUseSessionId, experimentsForUser: experimentsForUser, referralSequenceNumber: referralSequenceNumber, parentAccountNumber: parentAccountNumber ?? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, }; return globalMethods .callHttpClient({ method: endpoints.LogCustomEvent.method, endpoint: endpoints.LogCustomEvent.url, payload: payload, logApiCall: false, }) .then((response) => { return response; }); }, initializeSession(context, { userId, deviceId, sessionId, userAgent, referrer }) { var payload = { applicationName: applicationConfig.ANALYTICS_APPLICATION_NAME, userId: userId, deviceId: deviceId, sessionId: sessionId, userAgent: userAgent, operatorId: "WEB", userName: "SafeliteConceptFunnel", referrer: referrer, }; return globalMethods .callHttpClient({ method: endpoints.InitializeSession.method, endpoint: endpoints.InitializeSession.url, payload: payload, logApiCall: false, }) .then((response) => { return response; }); }, // Misc Actions setReferralInformation(context, { referralNumber, referralDate, referralCorrelationId, eon }) { 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_EON, eon); }, GetExperimentsByUser(context, { userId }) { return globalMethods.callHttpClient({ method: endpoints.GetExperimentsByUser.method, endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`, payload: {}, }); }, async runExperimentsForTrigger( context, { payload: { userId, triggerEvent, triggerValue }, pageNameToLog } ) { if (triggerEvent == experimentTriggers.SITE_ENTRY) { context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true); } var payload = { applicationName: applicationConfig.APPLICATION_NAME, userId: userId, triggerEvent: triggerEvent, triggerValue: triggerValue, experimentOrder: context.getters.experimentOrder, }; const response = await globalMethods.callHttpClient({ method: endpoints.RunExperimentsForTrigger.method, endpoint: endpoints.RunExperimentsForTrigger.url, payload: payload, logApiCall: true, pageNameToLog: pageNameToLog, }); context.commit(storeMutations.UPDATE_EXPERIMENTS, response.data.experiments); }, getEvoxImage(context, { relativeUrl }) { return globalMethods.callHttpClient({ method: endpoints.GetPageData.method, endpoint: relativeUrl, payload: {}, }); }, // PartsOrQuestions API Actions async getPartsOrQuestions(context, { pageNameToLog }) { const vehicle = context.getters.vehicle; const damage = context.getters.damage; const order = context.state.order; const carId = vehicle.carId; const glassArray = damage.glassToReplace; const zipCode = order.serviceLocation.zipCode; const vin = vehicle.vin; const serviceType = order.serviceLocation?.appointmentType; const referralSeqNumber = order.referralSequenceNumber; // create a new array to avoid mutating state const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray); const response = await globalMethods.callHttpClient({ method: endpoints.GetPartsOrQuestions.method, endpoint: endpoints.GetPartsOrQuestions.url, payload: { carId: carId, glassPieces: glassArrayForPayload, zip: zipCode, vin: vin, serviceType: serviceType, referralSeqNumber: referralSeqNumber, }, logApiCall: true, pageNameToLog: pageNameToLog, }); // Flatten location and name properties response.data.partsOrQuestions = convertGlassPieceNamingFromApi( response.data.partsOrQuestions ); return response; }, // Parts API Actions async getParts(context, { pageNameToLog }) { const vehicle = context.getters.vehicle; const damage = context.getters.damage; const order = context.state.order; 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; // create a new array to avoid mutating state const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray); const resultsArrayForPayload = convertResultsForApi(resultsArray); 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, }, logApiCall: true, pageNameToLog: pageNameToLog, }); // Flatten location and name properties response.data.glassPieceParts = convertGlassPieceNamingFromApi( response.data.glassPieceParts ); return response; }, async getWipers(context, { payload, pageNameToLog }) { const carId = payload.carId; const serviceZipCode = payload.serviceZipCode; const response = await globalMethods .callHttpClient({ method: endpoints.GetWipers.method, endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`, logApiCall: true, pageNameToLog: pageNameToLog, }) .catch((error) => { // The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow return []; }); syncLineItemIds(response.data, context.getters.order.lineItems.vaps); return response; }, async getRainDefense(context, { pageNameToLog }) { const response = await globalMethods.callHttpClient({ method: endpoints.GetRainDefense.method, endpoint: endpoints.GetRainDefense.url, logApiCall: true, pageNameToLog: pageNameToLog, }); syncLineItemIds([response.data], context.getters.order.lineItems.vaps); return response; }, getMobileFeePart(context, { pageNameToLog }) { const serviceType = context.getters.damage.isRepair ? "Repair" : "Install"; const facilityType = "Mobile"; const parentAccountNumber = context.getters.payment.parentAccountNumber; const billToAccountNumber = context.getters.payment.billToAccountNumber ? context.getters.payment.billToAccountNumber : applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER; const order = context.getters.order; const coverageStatus = coverageStatusEnum(order.payment?.insuranceCoverage?.coverageStatus); const coverageType = coverageTypeEnum(order.payment?.insuranceCoverage?.coverageType); const isItacOptimized = order.policy?.isItac ?? false; const zipCode = order.serviceLocation?.provider?.address?.zipCode ?? order.serviceLocation?.zipCode; var providerNumber = order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu; if (providerNumber.startsWith("00") && providerNumber.length > 5) { providerNumber = providerNumber.substring(1); } var endPoint = `${endpoints.GetMobileFeePart.url}/?serviceType=${serviceType}&facilityType=${facilityType}&parentAccountNumber=${parentAccountNumber}&billToAccountNumber=${billToAccountNumber}&providerNumber=${providerNumber}&isItacOptimized=${isItacOptimized}&zipCode=${zipCode}`; if (coverageStatus) { endPoint = `${endPoint}&coverageStatus=${coverageStatus}`; } if (coverageType) { endPoint = `${endPoint}&coverageType=${coverageType}`; } return globalMethods.callHttpClient({ method: endpoints.GetMobileFeePart.method, endpoint: endPoint, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getServicePackageDiscountPart(context, { pageNameToLog }) { const damage = context.getters.damage; const damageType = damage.isRepair ? "Repair" : "Replace"; const glassPieces = convertGlassPieceNamingForApi(damage.glassToReplace); return globalMethods .callHttpClient({ method: endpoints.GetServicePackageDiscountPart.method, endpoint: endpoints.GetServicePackageDiscountPart.url, payload: { glassPieces: glassPieces, damageType: damageType, }, logApiCall: true, pageNameToLog: pageNameToLog, }) .then((response) => { return response; }); }, getServiceabilityDetails(context, { payload: { serviceZipCode }, pageNameToLog }) { const escapeRecalibrationType = (rt) => rt.split("&").join("%26"); const partialLineItemsObjects = context.getters.order.lineItems.glassParts?.map( (lineItem) => ({ partNumber: lineItem.partNumber, recalibrationType: lineItem.recalibrationType && isRecalPartOrHasChildRecalPart(lineItem) ? escapeRecalibrationType(lineItem.recalibrationType) : undefined, }) ); var lineItems = null; if (partialLineItemsObjects) { lineItems = buildQueryStringParameterFromArrayOfComplexObjects( partialLineItemsObjects, "lineItems" ); } const vehicle = context.getters.vehicle; const carId = vehicle.carId; const damage = context.getters.damage; const glassArray = convertGlassPieceNamingForApi(damage.glassToReplace); const glassPieces = buildQueryStringParameterFromArrayOfComplexObjects( glassArray, "glassPieces" ); const parentAccountNumber = context.getters.order.payment.parentAccountNumber ?? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER; const referralSequenceNumber = context.getters.order.referralSequenceNumber; var endPoint = `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&parentAccountNumber=${parentAccountNumber}&referralSequenceNumber=${referralSequenceNumber}&applicationName=${applicationConfig.ANALYTICS_APPLICATION_NAME}`; if (lineItems) { endPoint += `&${lineItems}`; } if (glassPieces) { endPoint += `&${glassPieces}`; } return globalMethods.callHttpClient({ method: endpoints.GetServiceabilityDetails.method, endpoint: endPoint, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getProviders(context, { payload: { serviceZipCode }, pageNameToLog }) { const damageType = context.getters.damage.isRepair ? "Repair" : "Replace"; const accountNumber = context.getters.order.payment.parentAccountNumber ?? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER; const carId = context.getters.order.vehicle.carId; const partsWithRecal = getTopLevelPartsWithRecal( context.getters.order.lineItems.glassParts ); const windshieldPartWithRecal = partsWithRecal?.length > 0 ? partsWithRecal[0] : null; const shopRadiusInMiles = 100; let url = `${endpoints.GetProviders.url}/${serviceZipCode}/${damageType}/${shopRadiusInMiles}/${accountNumber}/true/${carId}`; if (windshieldPartWithRecal) { url += `/${windshieldPartWithRecal.partNumber}`; } return globalMethods.callHttpClient({ method: endpoints.GetProviders.method, endpoint: url, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getSupportingItems(context, { pageNameToLog }) { const glassPartsArray = context.getters.lineItems.glassParts ?? []; const carId = context.getters.vehicle.carId; const isRepair = context.getters.damage.isRepair; const numberOfChips = context.getters.damage.numberOfChips; return globalMethods.callHttpClient({ method: endpoints.GetSupportingItems.method, endpoint: endpoints.GetSupportingItems.url, payload: { carId: carId, damageType: isRepair ? "Repair" : "Replace", parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, parts: glassPartsArray, numberOfRepairChips: isRepair ? numberOfChips : 0, }, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getCapabilityQuestions(context, { payload: { carId, partNumber }, pageNameToLog }) { return globalMethods.callHttpClient({ method: endpoints.GetCapabilityQuestions.method, endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getPartFromCapabilityQuestionAnswer(context, { payload, pageNameToLog }) { const glassLocation = payload; const pageData = context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS); const part = pageData.partsOrQuestions.find((x) => x.glassLocation === glassLocation) .parts[0]; const capabilityQuestionAnswers = context.getters.damage.capabilityQuestionAnswers; const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find( (x) => x.glassLocation === glassLocation ); return globalMethods.callHttpClient({ method: endpoints.GetPartFromCapabilityAnswer.method, endpoint: endpoints.GetPartFromCapabilityAnswer.url, payload: { part, capabilityAnswerResults: capabilityQuestionAnswersForPart, }, logApiCall: true, pageNameToLog: pageNameToLog, }); }, getShopTimeSlots( context, { payload: { startDate, endDate, shopAppointmentType, providerNumber }, pageNameToLog } ) { const order = context.state.order; const vehicle = context.state.order.vehicle; const payment = context.state.order.payment; const lineItems = getFlattenedLineItemsWithGlassPartTag(order.lineItems); const glassPieces = order.damage.glassToReplace ? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace) : []; var payload = { zipCode: order.serviceLocation.provider.zipCode, providerNumber: providerNumber, startDate: startDate, endDate: endDate, shopAppointmentType: shopAppointmentType, applicationName: applicationConfig.APPLICATION_NAME, parentAccountNumber: payment.parentAccountNumber, carId: vehicle.carId, lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, billToAccountNumber: context.getters.payment.billToAccountNumber, coverage: { status: payment.insuranceCoverage.coverageStatus, deductible: order.policy.currentDeductible, additionalAuthFlag: order.policy.additionalAuthFlag, }, partSelection: { hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length, hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length, hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length, hasManuallySelectedParts: !!context.state.applicationUser.pageData["vehicle-parts"]?.partsOrQuestions .length, }, vehicle: { year: vehicle.year, make: vehicle.make, model: vehicle.model, style: vehicle.style, vin: vehicle.vin ?? "", }, }; return globalMethods.callHttpClient({ method: endpoints.GetShopTimeSlots.method, endpoint: endpoints.GetShopTimeSlots.url, payload: payload, logApiCall: true, pageNameToLog: pageNameToLog, additionalSuccessEventDataHandler: (response) => getTimeSlotsAdditionalEventData( response.data.provisionalTriggers, order.serviceLocation.zipCode, response.data.days?.[0]?.date, shopAppointmentType ), }); }, getMobileTimeSlots(context, { payload: { startDate, endDate }, pageNameToLog }) { const order = context.state.order; const vehicle = context.state.order.vehicle; const payment = context.state.order.payment; const lineItems = getFlattenedLineItemsWithGlassPartTag(order.lineItems); const glassPieces = order.damage.glassToReplace ? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace) : []; var payload = { startDate: startDate, endDate: endDate, applicationName: applicationConfig.APPLICATION_NAME, parentAccountNumber: payment.parentAccountNumber, carId: vehicle.carId, lineItems: lineItems, glassPieces: glassPieces, eon: order.eon, billToAccountNumber: context.getters.payment.billToAccountNumber, coverage: { status: payment.insuranceCoverage.coverageStatus, deductible: order.policy.currentDeductible, additionalAuthFlag: order.policy.additionalAuthFlag, }, partSelection: { hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length, hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length, hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length, hasManuallySelectedParts: !!context.state.applicationUser.pageData["vehicle-parts"]?.partsOrQuestions .length, }, vehicle: { year: vehicle.year, make: vehicle.make, model: vehicle.model, style: vehicle.style, vin: vehicle.vin ?? "", }, zipCode: order.serviceLocation.zipCode, }; return globalMethods.callHttpClient({ method: endpoints.GetMobileTimeSlots.method, endpoint: endpoints.GetMobileTimeSlots.url, payload: payload, logApiCall: true, pageNameToLog: pageNameToLog, additionalSuccessEventDataHandler: (response) => getTimeSlotsAdditionalEventData( response.data.provisionalTriggers, order.serviceLocation.zipCode, response.data.days?.[0]?.date ), }); }, getMobilePremiumFee(context, { pageNameToLog }) { const damageType = context.getters.damage.isRepair ? "Repair" : "Replace"; const paymentType = context.getters.order.payment.isInsurance ? "Insurance" : "Cash"; return globalMethods.callHttpClient({ method: endpoints.GetMobilePremiumFee.method, endpoint: `${endpoints.GetMobilePremiumFee.url}/${paymentType}/${damageType}`, logApiCall: true, pageNameToLog: pageNameToLog, }); }, // Signing Service for Payment getSignature() { return globalMethods.callHttpClient({ method: endpoints.GetSignature.method, endpoint: endpoints.GetSignature.url, }); }, // Session API Actions saveSession(context, { pageNameToLog, payload }) { const vehicle = context.getters.vehicle; const damage = context.getters.damage; const order = context.state.order; const applicationUser = context.getters.applicationUser; const lineItems = context.state.order.lineItems; const submitAfterSave = payload?.submitAfterSave === "true"; const createUnscheduledStatusWorkOrderForPIA = payload?.createUnscheduledStatusWorkOrderForPIA === "true"; // create a new array to avoid mutating state const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); //affiliate cookie save only when submitAfterSave const affiliateCookies = submitAfterSave ? applicationUser.affiliateCookies : null; return globalMethods.callHttpClient({ method: endpoints.SaveSession.method, endpoint: endpoints.SaveSession.url, payload: { submitAfterSave: submitAfterSave, userAgent: navigator.userAgent, applicationUser: { crmCustomerId: applicationUser.crmCustomerId, experiments: applicationUser.experiments, lastPage: applicationUser.lastPageVisited, pageData: applicationUser.pageData, savedSessionId: applicationUser.savedSessionId, affiliateCookies: affiliateCookies, }, order: { vehicle: { carId: vehicle.carId, year: vehicle.year, make: vehicle.make, model: vehicle.model, style: vehicle.style, vin: vehicle.vin, registration: { firstName: vehicle.registration.firstName, lastName: vehicle.registration.lastName, streetAddress: vehicle.registration.address, city: vehicle.registration.city, state: vehicle.registration.state, zipCode: vehicle.registration.zipCode, licensePlateNumber: vehicle.registration.licensePlate, }, }, customer: { emailAddress: order.customer.emailAddress, firstName: order.customer.firstName, lastName: order.customer.lastName, isSmsOptIn: order.customer.isSmsOptIn, phoneNumber: order.customer.phoneNumber, }, damage: { numberOfChips: damage.numberOfChips, glassToReplace: newGlassToReplace, isRepair: damage.isRepair, partQuestionAnswers: order.damage.partQuestionAnswers, moldingQuestionAnswers: order.damage.moldingQuestionAnswers, capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers, }, lineItems: { glassParts: lineItems.glassParts, supportingItems: lineItems.supportingItems, vaps: lineItems.vaps, serverData: lineItems.serverData, promos: lineItems.promos, }, payment: { InsuranceCoverage: { isVerified: order.payment.insuranceCoverage.isVerified ?? false, coverageStatus: order.payment.insuranceCoverage.coverageStatus?.toString(), coverageVerificationType: order.payment.insuranceCoverage.coverageVerificationType, coverageSubStatus: order.payment.insuranceCoverage.coverageSubStatus, }, isInsurance: order.payment.isInsurance, parentAccountNumber: order.payment.parentAccountNumber, billToAccountNumber: order.payment.billToAccountNumber, inactivePromos: order.payment.inactivePromos, isCreditCard: order.payment.piaType == paymentMethods.CREDIT_CARD ? true : false, isPaypal: order.payment.piaType == paymentMethods.PAYPAL ? true : false, isAfterPay: order.payment.piaType == paymentMethods.AFTERPAY ? true : false, isApplePay: order.payment.piaType == paymentMethods.APPLE_PAY ? true : false, paypalToken: order.payment.paypalToken, nextGenSettledAmount: order.payment.nextGenSettledAmount, ccToken: { subscriptionId: order.payment.ccToken.subscriptionId, expMonth: order.payment.ccToken.expMonth, expYear: order.payment.ccToken.expYear, cardType: order.payment.ccToken.cardType, billToPostalCode: order.payment.ccToken.billToPostalCode, billToFirstName: order.payment.ccToken.billToFirstName, billToLastName: order.payment.ccToken.billToLastName, referenceNumber: order.payment.ccToken.referenceNumber, authCode: order.payment.ccToken.authCode, transactionId: order.payment.ccToken.transactionId, transReferenceNumber: order.payment.ccToken.transReferenceNumber, lastFour: order.payment.ccToken.lastFour, }, }, policy: { isItac: order.policy?.isItac, isNoComp: order.policy?.isNoComp, }, serviceLocation: { streetAddress: order.serviceLocation.address, streetAddress2: order.serviceLocation.address2, city: order.serviceLocation.city, state: order.serviceLocation.state, zipCode: order.serviceLocation.zipCode, zipCodeCtu: order.serviceLocation.zipCodeCtu, appointmentType: order.serviceLocation.appointmentType, isVehicleProtected: order.serviceLocation.isVehicleProtected, provider: { providerNumber: order.serviceLocation.provider?.providerNumber, address: { streetAddress: order.serviceLocation.provider?.address?.streetAddress, city: order.serviceLocation.provider?.address?.city, state: order.serviceLocation.provider?.address?.state, zipCode: order.serviceLocation.provider?.address?.zipCode, zipCodeCtu: order.serviceLocation.provider?.address?.zipCodeCtu, }, }, techNotes: order.serviceLocation.techNotes, }, schedule: { date: order.schedule?.date, startTime: order.schedule?.startTime, endTime: order.schedule?.endTime, routeCode: order.schedule?.routeCode, jobMaxMinutes: order.schedule?.jobMaxMinutes, jobMinMinutes: order.schedule?.jobMinMinutes, }, referralCorrelationId: order.referralCorrelationId, referralDate: order.referralDate, referralNumber: order.referralNumber?.toString(), referralSequenceNumber: order.referralSequenceNumber, eon: order.eon, createUnscheduledStatusWorkOrderForPIA: createUnscheduledStatusWorkOrderForPIA, lockToken: order.lockToken, isRecalAckOptIn: order.isRecalAckOptIn, }, }, logApiCall: true, pageNameToLog: pageNameToLog, additionalSuccessEventDataHandler: (response) => "Email provided: " + (order.customer.emailAddress ? "true" : "false"), }); }, loadSession( context, { payload: { savedSessionId, referralNumber, referralDate, parentAccountNumber, referralCorrelationId, isConceptInsurance, }, pageNameToLog, } ) { const order = context.state.order; var dtParts = referralDate.split("-"); const year = dtParts[0]; const month = dtParts[1]; const day = dtParts[2].substring(0, 2); const loadDate = `${year}-${month}-${day}`; return globalMethods .callHttpClient({ method: endpoints.LoadSession.method, endpoint: endpoints.LoadSession.url, payload: { savedSessionId: savedSessionId?.toString(), referralNumber: referralNumber?.toString(), referralDate: loadDate, parentAccountNumber: parentAccountNumber?.toString(), referralCorrelationId: referralCorrelationId, }, logApiCall: true, pageNameToLog: pageNameToLog, }) .then( async (response) => { // Flatten location and name properties response.data.order.damage?.glassToReplace?.map((glass) => { glass.glassLocation = glass.location; glass.glassName = glass.name; delete glass.location; delete glass.name; return glass; }); // clear the state if the existing EON does not equal what is returned from loadSession if ( context.state.order.eon && context.state.order.eon != response.data.order.eon ) { context.commit(storeMutations.RESET_STATE); } context.commit( storeMutations.UPDATE_STATE_WITH_ORDER_INFORMATION, response.data ); await resetScheduleIfUnavailable(context, response.data.order, pageNameToLog); return response; }, (error) => { deleteFunnelCookie(); context.commit(storeMutations.RESET_STATE); } ); }, saveCCToken(context, ccToken) { context.commit(storeMutations.UPDATE_CCTOKEN, ccToken); }, saveNextGenSettledAmount(context, nextGenSettledAmount) { context.commit(storeMutations.UPDATE_NEXTGEN_SETTLED_AMOUNT, nextGenSettledAmount); }, savePaypalToken(context, ppToken) { context.commit(storeMutations.UPDATE_PAYPAL_TOKEN, ppToken); }, // Business domain actions // Vehicle saveVehicle( context, { year, make, model, style, carId, category, imageUrl, imageVifNumber, imageVifColor } ) { if ( context.state.order.vehicle.year != year || context.state.order.vehicle.make != make || context.state.order.vehicle.model != model || context.state.order.vehicle.style != style ) { context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); context.commit(storeMutations.UPDATE_VEHICLE_VIN, null); context.commit(storeMutations.UPDATE_YEAR, year); context.commit(storeMutations.UPDATE_MAKE, make); context.commit(storeMutations.UPDATE_MODEL, model); context.commit(storeMutations.UPDATE_STYLE, style); context.commit(storeMutations.UPDATE_CAR_ID, carId); context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, category); context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, imageUrl); context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, imageVifNumber); context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, imageVifColor); } }, saveVehicleDamage( context, { isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount } ) { const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort(); const isGlassToReplaceTheSame = context.state.order.damage.glassToReplace?.length === selectedGlassToReplace.length && context.state.order.damage.glassToReplace .slice() .sort() .every( (obj, index) => obj.glassLocation === selectedGlassPassedInSorted[index].glassLocation && obj.glassName === selectedGlassPassedInSorted[index].glassName ); const isWindshieldRepairTheSame = isWindshieldRepair === context.state.order.damage.isRepair; const isChipCountTheSame = selectedWindshieldChipCount === context.state.order.damage.numberOfChips; const isDamageChanging = !isGlassToReplaceTheSame || !isWindshieldRepairTheSame || (isWindshieldRepair && !isChipCountTheSame); if (isDamageChanging) { //Reset dependent state when changing context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); // Save new values context.commit(storeMutations.UPDATE_IS_REPAIR, isWindshieldRepair); context.commit( storeMutations.UPDATE_NUMBER_OF_CHIPS, isWindshieldRepair ? parseInt(selectedWindshieldChipCount) : null ); context.commit(storeMutations.UPDATE_GLASS_TO_REPLACE, selectedGlassToReplace); } }, // Vin lookup saveVinLookup(context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) { //Reset dependent state when changing if (vehicleInfo.vin !== context.state.order.vehicle.vin) { context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); context.dispatch(storeActions.RESET_PARTS_STATE_AND_DEPENDENCIES); if (!isSelectedGlassAvailableForVehicle) { context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); } //Save new values context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo); context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo); } }, saveRegistrationLicensePlateLookup( context, { isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo } ) { //Reset dependent state when changing if ( registrationInfo?.licensePlate !== context.state.order.vehicle.registration?.licensePlate ) { context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); if (!isSelectedGlassAvailableForVehicle) { context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); } context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo); if (registrationInfo) { context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo); // only update name information if there isn't a value in state already if (!context.getters.order.customer.firstName) { context.commit(storeMutations.UPDATE_CUSTOMER_DETAILS, { firstName: registrationInfo.firstName, lastName: registrationInfo.lastName, }); } } } }, saveRegistrationAddressLookup( context, { isSelectedGlassAvailableForVehicle, vehicleInfo, customerInfo } ) { //Reset dependent state when changing if (vehicleInfo.vin !== context.state.order.vehicle.vin) { context.dispatch(storeActions.RESET_REGISTRATION_STATE_AND_DEPENDENCIES); if (!isSelectedGlassAvailableForVehicle) { context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); } } context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo); // only update name information if there isn't a value in state already if (!context.getters.order.customer.firstName && customerInfo) { context.commit(storeMutations.UPDATE_CUSTOMER_DETAILS, { firstName: customerInfo.firstName, lastName: customerInfo.lastName, }); } }, savePartQuestionAnswers(context, partQuestionAnswersArray) { // if part question answers have changed, reset subsequent question answers const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue( context.getters.damage.partQuestionAnswers, "result" ); const sortedPartQuestionAnswersArray = sortArrayOfObjectsByPropertyValue( partQuestionAnswersArray, "result" ); const havePartQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedPartQuestionAnswersArray.length || !sortedPreviousResultsArray?.every( (x, i) => x.result === sortedPartQuestionAnswersArray[i].result ); if (havePartQuestionAnswersChanged) { context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES); context.commit(storeMutations.UPDATE_GLASS_PARTS, null); context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null); context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null); context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.VEHICLE_PARTS, data: null, }); context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null, }); context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null, }); } //Save new values context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray); }, resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) { const partsOrQuestionsDataToCompareWith = context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ?? context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS)?.partsOrQuestions ?? []; function getAllPartNumbers(partsOrQuestions) { return partsOrQuestions[0]?.parts ? [...partsOrQuestions] .map((glass) => glass.parts) .flat() .map((part) => part.partNumber) .filter((partNumber) => !partNumber.toUpperCase().includes("FEE")) .sort() .join(",") : []; } const previouslySelectedPartNumbers = getAllPartNumbers(partsOrQuestionsDataToCompareWith); const currentlySelectedPartNumbers = getAllPartNumbers(matchedParts); const haveSelectedVehiclePartsChanged = previouslySelectedPartNumbers !== currentlySelectedPartNumbers; if (haveSelectedVehiclePartsChanged) { context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES); context.commit(storeMutations.UPDATE_GLASS_PARTS, null); context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null); context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, null); context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.MOLDING_QUESTIONS, data: null, }); context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null, }); } }, saveMoldingQuestionAnswers(context, moldingQuestionAnswers) { const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue( context.getters.damage.moldingQuestionAnswers, "partNum" ); const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue( moldingQuestionAnswers, "partNum" ); const haveMoldingQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length || !sortedPreviousResultsArray?.every( (x, i) => x.partNum === sortedMoldingQuestionAnswersArray[i].partNum ); if (haveMoldingQuestionAnswersChanged) { context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES); context.commit(storeMutations.UPDATE_GLASS_PARTS, null); context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null); context.commit(storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, null); context.commit(storeMutations.UPDATE_PAGE_DATA, { page: fmgPageValues.CAPABILITY_QUESTIONS, data: null, }); } //Save new values context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers); }, saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) { const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue( context.getters.damage.capabilityQuestionAnswers, "result" ); const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue( capabilityQuestionAnswers, "result" ); const haveCapabilityQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedCapabilityQuestionAnswersArray.length || !sortedPreviousResultsArray?.every( (x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result ); if (haveCapabilityQuestionAnswersChanged) { context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES); context.commit(storeMutations.UPDATE_GLASS_PARTS, null); context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null); } //Save new values context.commit( storeMutations.UPDATE_CAPABILITY_QUESTION_ANSWERS, capabilityQuestionAnswers ); }, savePaymentType(context, isInsurance) { if (isInsurance !== context.getters.payment.isInsurance) { context.commit(storeMutations.RESET_PAYMENT_METHOD_CHOICE); } context.commit(storeMutations.UPDATE_IS_INSURANCE, isInsurance); }, savePaymentMethodChoice(context, paymentMethod) { const isPia = paymentMethod !== paymentMethods.LATER; context.commit(storeMutations.UPDATE_IS_PIA, isPia); context.commit(storeMutations.UPDATE_PIA_TYPE, isPia ? paymentMethod : null); }, saveIsRecalAckOptIn(context, isRecalAckOptIn) { context.commit(storeMutations.UPDATE_IS_RECAL_ACK_OPT_IN, isRecalAckOptIn); }, saveParentAccountNumber(context, parentAccountNumber) { context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber); }, saveBillToAccountNumber(context, billToAccountNumber) { context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber); }, saveSupportingItems(context, supportingItems) { syncLineItemIds(supportingItems, context.state.order.lineItems.supportingItems); if (!supportingItemsEqual(supportingItems, context.state.order.lineItems.supportingItems)) { context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES); } addGuidToLineItemsIfNotAlreadyThere(supportingItems); context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems); }, saveSupportingItemsSuppressingStateResetting(context, supportingItems) { addGuidToLineItemsIfNotAlreadyThere(supportingItems); context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems); }, saveVaps(context, vaps) { addGuidToLineItemsIfNotAlreadyThere(vaps); context.commit(storeMutations.UPDATE_VAPS, vaps); }, // Manage promo saving to ensure a promoCode never ends up in both active and inactive saveActiveAndOrInactivePromos(context, { activePromos = null, inactivePromos = null }) { if (inactivePromos) { // Clean up inactivePromos // Remove bundle identifier inactivePromos = inactivePromos.map((promoCode) => getPromoCodeWithoutBundleIdentifier(promoCode) ); // Remove duplicates inactivePromos = inactivePromos.filter( (promoCode, index) => inactivePromos.indexOf(promoCode) === index ); } activePromos = activePromos?.slice(0); inactivePromos = inactivePromos?.slice(0); let activePromosToSave; let inactivePromosToSave; if (!activePromos && !inactivePromos) { // Allow double null to save empty arrays to store activePromosToSave = []; inactivePromosToSave = []; } else if (activePromos && inactivePromos) { // Prioritize active promos when both inactive and active are supplied activePromosToSave = activePromos; inactivePromosToSave = removeCurrentlyActivePromoCodesFromInactivePromos( activePromosToSave, inactivePromos ); } else if (!activePromos) { // Only inactivePromos supplied inactivePromosToSave = inactivePromos; activePromosToSave = (context.getters.lineItems.promos ?? []).filter((activePromo) => { return !inactivePromosToSave.includes( getPromoCodeWithoutBundleIdentifier(activePromo.promoCode) ); }); } else if (!inactivePromos) { // Only activePromos supplied activePromosToSave = activePromos; inactivePromosToSave = removeCurrentlyActivePromoCodesFromInactivePromos( activePromosToSave, context.getters.payment.inactivePromos ?? [] ); } context.commit(storeMutations.UPDATE_PROMOS, activePromosToSave); context.commit(storeMutations.UPDATE_INACTIVE_PROMOS, inactivePromosToSave); }, // Price order actions async priceOrderItemsAndSaveServerData( context, { payload: { availableLineItems, serviceZipCode, serviceZipCodeCtu }, pageNameToLog } ) { const flattenedLineItemsWithChildParts = getFlattenedArrayOfLineItemsWithChildParts(availableLineItems); const lineItemsWithOnlyPartNumbers = flattenedLineItemsWithChildParts.map((lineItem) => ({ partNumber: lineItem.partNumber, })); const order = context.getters.order; var providerNumber = order.serviceLocation?.provider?.providerNumber ?? order.serviceLocation?.zipCodeCtu; if (providerNumber.startsWith("00") && providerNumber.length > 5) { providerNumber = providerNumber.substring(1); } const response = await globalMethods.callHttpClient({ method: endpoints.PriceOrderItems.method, endpoint: endpoints.PriceOrderItems.url, payload: { parentAccountNumber: order.payment?.parentAccountNumber, billToAccountNumber: order.payment?.billToAccountNumber ?? applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER, providerNumber: providerNumber, carId: order.vehicle.carId, year: order.vehicle.year, make: order.vehicle.make, model: order.vehicle.model, eon: order.eon, state: order.serviceLocation?.state, referralNumber: order.referralNumber, referralSequenceNumber: order.referralSequenceNumber, zipCode: order.serviceLocation?.zipCode, serviceZipCode: serviceZipCode ?? order.serviceLocation?.zipCode, referralDate: order.referralDate, isReplacement: !order.damage.isRepair, deductible: order.policy?.currentDeductible, coverageStatus: order.payment?.insuranceCoverage?.coverageStatus, lineItems: lineItemsWithOnlyPartNumbers, serverData: order.lineItems.serverData ? order.lineItems.serverData : "", }, logApiCall: true, pageNameToLog: pageNameToLog, }); context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData); availableLineItems = addPricesToLineItems(availableLineItems, response.data.lineItems); return availableLineItems; }, // Tax order actions async taxOrderItemsAndSaveServerData( context, { payload: { billToAccountNumber, providerNumber, appointmentType, serviceLocationCity, serviceLocationState, serviceLocationZipCode, pricedLineItems, }, pageNameToLog, } ) { const flattenedLineItemsWithChildParts = getFlattenedArrayOfLineItemsWithChildParts(pricedLineItems); const lineItemsWithOnlyPriceInfo = flattenedLineItemsWithChildParts.map((lineItem) => ({ partNumber: lineItem.partNumber, laborAmount: lineItem.laborAmount ?? 0, kitPrice: lineItem.kitPrice ?? 0, sellingPrice: lineItem.sellingPrice ?? 0, promoCode: lineItem.promoCode ?? null, })); const pricedLineItemsFormattedForRequest = buildQueryStringParameterFromArrayOfComplexObjects( lineItemsWithOnlyPriceInfo, "lineItems" ); let queryString = ""; if (appointmentType == "Mobile") { queryString = `ParentAccountNumber=${context.getters.order.payment.parentAccountNumber}` + `&BillToAccountNumber=${billToAccountNumber}` + `&ProviderNumber=${providerNumber}` + `&AppointmentType=${appointmentType}` + `&ServiceLocation.City=${serviceLocationCity}` + `&ServiceLocation.State=${serviceLocationState}` + `&ServiceLocation.ZipCode=${serviceLocationZipCode}` + `&${pricedLineItemsFormattedForRequest}`; } else { queryString = `ParentAccountNumber=${context.getters.order.payment.parentAccountNumber}` + `&BillToAccountNumber=${billToAccountNumber}` + `&ProviderNumber=${providerNumber}` + `&AppointmentType=${appointmentType}` + `&${pricedLineItemsFormattedForRequest}`; } const lineItemServerData = context.getters.order.lineItems.serverData; if (lineItemServerData) { queryString += `&ServerData=${encodeURIComponent(lineItemServerData)}`; } const response = await globalMethods.callHttpClient({ method: endpoints.TaxOrderItems.method, endpoint: `${endpoints.TaxOrderItems.url}?${queryString}`, logApiCall: true, pageNameToLog: pageNameToLog, }); context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData); pricedLineItems = addTaxesToPricedLineItems(pricedLineItems, response.data.taxedLineItems); return pricedLineItems; }, // The parameter is an array of ALL available front wipers and rain defense // for the vehicle. There is no need to confirm an addableVap is not already on the order // is an optional parameter if the lineItems in the store may not be up to date async validateOrderPromoAndSaveServerData( context, { payload: { promoCode, lineItemsToUse, addableVaps, useDefaultCashParentAccount = false, }, pageNameToLog, } ) { const order = context.getters.order; lineItemsToUse = lineItemsToUse ?? order.lineItems; addGuidToLineItemsIfNotAlreadyThere(lineItemsToUse.vaps); syncLineItemIds(addableVaps, lineItemsToUse.vaps); // addableVaps still won't have IDs if they weren't already in lineItemsToUse addGuidToLineItemsIfNotAlreadyThere(addableVaps); const requestObject = { promoCode: promoCode, addableVaps: addableVaps, order: { appointmentType: order.serviceLocation.appointmentType, carId: order.vehicle.carId, correlationId: order.referralCorrelationId, eon: order.eon, isInsurance: order.payment.isInsurance, isRepair: order.damage.isRepair, glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace), lineItemsOnOrder: getArrayOfAllLineItemsAndChildParts(lineItemsToUse), parentAccountNumber: useDefaultCashParentAccount ? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER : order.payment.parentAccountNumber, referralSequenceNumber: order.referralSequenceNumber, serviceState: order.serviceLocation.state, serverData: order.lineItems.serverData, vehicleYear: "" + order.vehicle.year, zipCodeOrProviderCtu: order.serviceLocation.appointmentType === "Inshop" ? order.serviceLocation.provider.address.zipCodeCtu : order.serviceLocation.zipCodeCtu, }, }; const validateResponse = await globalMethods .callHttpClient({ method: endpoints.ValidatePromo.method, endpoint: endpoints.ValidatePromo.url, payload: requestObject, logApiCall: true, pageNameToLog: pageNameToLog, }) .catch((error) => { // Validate promo will return 4xx errors when an invalid promo return error; }); if (validateResponse?.data?.serverData) { context.commit( storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, validateResponse.data.serverData ); } return validateResponse?.data; }, // All payload parameters are optional - will use store data if not provided async revalidateOrderPromosAndSaveServerData( context, { payload: { activePromosToUse, inactivePromosToUse, lineItemsToUse, useDefaultCashParentAccount = false, }, pageNameToLog, } ) { const order = context.getters.order; activePromosToUse = activePromosToUse ?? order.lineItems.promos; lineItemsToUse = lineItemsToUse ? deepClone(lineItemsToUse) : deepClone(order.lineItems); addGuidToLineItemsIfNotAlreadyThere(lineItemsToUse.vaps); lineItemsToUse.promos = activePromosToUse; inactivePromosToUse = inactivePromosToUse ?? order.payment.inactivePromos; inactivePromosToUse = removeCurrentlyActivePromoCodesFromInactivePromos( lineItemsToUse.promos, inactivePromosToUse ); let requestObject = { inactivePromos: inactivePromosToUse, order: { appointmentType: order.serviceLocation.appointmentType, carId: order.vehicle.carId, correlationId: order.referralCorrelationId, eon: order.eon, isInsurance: order.payment.isInsurance, isRepair: order.damage.isRepair, glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace), lineItemsOnOrder: getArrayOfAllLineItemsAndChildParts(lineItemsToUse), parentAccountNumber: useDefaultCashParentAccount ? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER : order.payment.parentAccountNumber, referralSequenceNumber: order.referralSequenceNumber, serviceState: order.serviceLocation.state, serverData: order.lineItems.serverData, vehicleYear: "" + order.vehicle.year, zipCodeOrProviderCtu: order.serviceLocation.appointmentType === "Inshop" ? order.serviceLocation.provider.address.zipCodeCtu : order.serviceLocation.zipCodeCtu, }, }; const revalidateResponse = await globalMethods.callHttpClient({ method: endpoints.RevalidatePromos.method, endpoint: endpoints.RevalidatePromos.url, payload: requestObject, logApiCall: true, pageNameToLog: pageNameToLog, }); context.commit( storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, revalidateResponse.data.lineItemsServerData ); return revalidateResponse?.data; }, /////////////////////////// // Account Service Calls // /////////////////////////// // List all insurance companies async getInsuranceCompanyList(context, { pageNameToLog }) { const insuranceCompanyList = await globalMethods.callHttpClient({ method: endpoints.GetInsuranceCompanyList.method, endpoint: endpoints.GetInsuranceCompanyList.url, payload: {}, logApiCall: true, pageNameToLog: pageNameToLog, }); return insuranceCompanyList.data.sort((a, b) => { const nameA = a.accountName.toUpperCase(); const nameB = b.accountName.toUpperCase(); if (nameA < nameB) { return -1; } if (nameA > nameB) { return 1; } return 0; }); }, // Get BillToAccountNumber async getBillToAccountNumber( context, { payload: { parentAccountNumber = context.getters.order.payment.parentAccountNumber, providerNumber = context.getters.order.serviceLocation.zipCodeCtu, isItac = context.getters.order.policy.isItac, }, pageNameToLog, } ) { if (!parentAccountNumber) { parentAccountNumber = applicationConfig.CASH_PARENT_ACCOUNT_NUMBER; } const queryString = `ParentAccountNumber=${parentAccountNumber}` + `&ProviderNumber=${providerNumber}` + `&IsItac=${isItac}`; const billToAccountNumberResponse = await globalMethods.callHttpClient({ method: endpoints.GetBillToAccountNumber.method, endpoint: `${endpoints.GetBillToAccountNumber.url}?${queryString}`, logApiCall: true, pageNameToLog: pageNameToLog, }); return billToAccountNumberResponse.data.toString(); }, ////////////////////////////////// // END OF Account Service Calls // ////////////////////////////////// // Misc order actions saveSchedule(context, scheduleInfo) { context.commit(storeMutations.UPDATE_SCHEDULE, scheduleInfo); }, saveCustomerDetails(context, customerDetails) { context.commit(storeMutations.UPDATE_CUSTOMER_DETAILS, customerDetails); }, saveServiceZipCodeInfo(context, serviceZipCodeInfo) { if ( context.state.order.serviceLocation && serviceZipCodeInfo.zipCode !== context.state.order.serviceLocation.zipCode ) { context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES); context.commit(storeMutations.RESET_SERVICE_LOCATION_MOBILE_ADDRESS); } context.commit(storeMutations.UPDATE_SERVICE_ZIP, serviceZipCodeInfo); }, saveServiceLocation(context, serviceLocationInfo) { if (context.state.order.serviceLocation) { if ( serviceLocationInfo.zipCode !== context.state.order.serviceLocation.zipCode || !providersEqual( serviceLocationInfo.provider, context.state.order.serviceLocation.provider ) || serviceLocationInfo.appointmentType !== context.state.order.serviceLocation.appointmentType ) { context.commit(storeMutations.RESET_SCHEDULE); context.commit(storeMutations.RESET_PAYMENT_METHOD_CHOICE); } } context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo); }, saveServiceLocationTechNotes(context, techNotesInfo) { context.commit(storeMutations.UPDATE_SERVICE_LOCATION_TECH_NOTES, techNotesInfo); }, saveEmail(context, email) { context.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, email === "" ? null : email); }, saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) { //Reset dependent state when changing if (vehicleInfo.vin !== context.state.order.vehicle.vin) { if (!isSelectedGlassAvailableForVehicle) { context.dispatch(storeActions.RESET_DAMAGE_STATE_AND_DEPENDENCIES); } //Save new values context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo); } }, saveGlassParts(context, parts) { if (!deepEqual(parts, context.state.order.lineItems.glassParts)) { context.dispatch(storeActions.RESET_SERVICE_LOCATION_STATE_AND_DEPENDENCIES); } addGuidToLineItemsIfNotAlreadyThere(parts); context.commit(storeMutations.UPDATE_GLASS_PARTS, parts); }, saveGlassPartsSuppressingStateResetting(context, parts) { context.commit(storeMutations.UPDATE_GLASS_PARTS, parts); }, clearVin(context) { context.commit(storeMutations.UPDATE_VEHICLE_VIN, null); }, isVinOptionalVehicle(context) { //Optional for carIds with only a single windshield if (singleWindshieldCarIds.find((item) => item === context.state.order.vehicle.carId)) { return true; } //Optional for specific YMMSs switch (context.state.order.vehicle.make.toLowerCase()) { case "mercedes benz": case "volkswagen": case "audi": case "porsche": return true; default: } if ( context.state.order.vehicle.make.toLowerCase() === "bmw" && context.state.order.vehicle.year <= 2017 ) return true; return false; }, createSubmittedOrder(context) { if (window.sessionStorage.getItem("submittedOrder") !== null) { return; } // create a submitted order object from vuex. const submittedOrder = context.state.order; const experiments = context.state.applicationUser.experiments; const affiliateCookies = context.state.applicationUser.affiliateCookies; // set to local storage window.sessionStorage.setItem("submittedOrder", JSON.stringify(submittedOrder)); window.sessionStorage.setItem("createNewSessionForHeritage", true); // clear vuex context.commit(storeMutations.RESET_STATE); // delete cookie deleteFunnelCookie(); //restore user's experiments context.commit(storeMutations.UPDATE_EXPERIMENTS, experiments); //clear externalParameter session storage window.sessionStorage.removeItem("externalParameterState"); //restore affiliate cookies context.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies); }, resetSubmittedOrder(context) { // clear from local storage window.sessionStorage.removeItem("submittedOrder"); }, resetExternalParameterState(context) { if (context.getters.isExternalParameter) { context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_VEHICLE_STATE); context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_DAMAGE_STATE); context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_ESTIMATE_STATE); context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_SERVICEZIP_STATE); context.commit(storeMutations.RESET_EXTERNAL_PARAMETER_QUOTE_STATE); context.commit(storeMutations.RESET_IS_EXTERNAL_PARAMETER); } }, updateExternalParameterMMS(context, externalParameterMMS) { context.commit( storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE, externalParameterMMS.externalParameterMake ); context.commit( storeMutations.UPDATE_EXTERNAL_PARAMETER_MODEL, externalParameterMMS.externalParameterModel ); context.commit( storeMutations.UPDATE_EXTERNAL_PARAMETER_STYLE, externalParameterMMS.externalParameterStyle ); }, saveLoggingOption(context, loggingOption) { var option = false; if (loggingOption != null) { option = loggingOption == "true" ? true : false; } context.commit(storeMutations.UPDATE_LOGGING_OPTION, option); }, async getRecalPartsAndSaveToLineItems(context, { pageNameToLog }) { // identify each part that needs recal const glassParts = context.state.order?.lineItems?.glassParts ? deepClone(context.state.order.lineItems.glassParts) : []; for (let i = 0; i < glassParts.length; i++) { // does this part need recal? const needsRecal = !!glassParts[i].requiresRecalibration && !!glassParts[i].recalibrationType; if (needsRecal) { const recalType = glassParts[i].recalibrationType; const parentAccountNumber = context.state.order.payment.parentAccountNumber ?? applicationConfig.CASH_PARENT_ACCOUNT_NUMBER; // Get part from API const urlExtension = `${context.state.order.vehicle.carId}/${glassParts[i].partNumber}/${recalType}/${parentAccountNumber}/${context.state.order.serviceLocation.zipCode}/${applicationConfig.ANALYTICS_APPLICATION_NAME}/${context.state.order.referralSequenceNumber}`; const recalPartResponse = await globalMethods.callHttpClient({ method: endpoints.GetRecalPart.method, endpoint: `${endpoints.GetRecalPart.url}/${urlExtension}`, payload: {}, pageNameToLog: pageNameToLog, }); // If any parts retrieved, add as children to the glass part. if ( recalPartResponse.status === 200 && recalPartResponse.data.recalibrationParts?.length > 0 ) { if (!glassParts[i].childParts) { glassParts[i].childParts = []; } glassParts[i].childParts.push(...recalPartResponse.data.recalibrationParts); context.dispatch(storeActions.SAVE_GLASS_PARTS, glassParts); } } } }, }; export default createStore({ plugins: [ createPersistedState(), sharedMutations({ predicate: [...Object.values(storeMutations)], }), ], // IMPORTANT: Be VERY careful when modifying these fields for at least a few reasons: // * The CMS can reference the fields by name // * Return users may have a previous "version" of the model, and we don't want // them to have a breaking experience, because the model might have changed. state, mutations, getters, actions, }); // Private Functions function getHasRecalibrationPart(state) { return containsRecalParts(state.order.lineItems); } function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) { if (!arrayOfObjects) return null; return arrayOfObjects.sort((a, b) => { if (a[propertyName] < b[propertyName]) return -1; else if (a[propertyName] > b[propertyName]) return 1; else return 0; }); } function convertGlassPieceNamingForApi(glassArray) { 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) { return glassArray; } const converted = []; glassArray.forEach((glass) => { converted.push({ location: glass.glassLocation, name: glass.glassName, }); }); return converted; } function convertResultsForApi(resultsArray) { if (!resultsArray) return []; const converted = []; resultsArray.forEach((answer) => { converted.push({ location: answer.glassLocation, name: answer.glassName, result: answer.result, }); }); return converted; } function convertGlassPieceNamingFromApi(glassArray) { glassArray.forEach((glass) => { glass.glassLocation = glass.glassPiece.location; glass.glassName = glass.glassPiece.name; delete glass.glassPiece; return glass; }); return glassArray; } function addPricesToLineItems(lineItems, pricingLineItems) { lineItems.forEach((lineItem) => { const lineItemIndex = pricingLineItems.findIndex( (pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber ); if (lineItem.childParts) { addPricesToLineItems(lineItem.childParts, pricingLineItems); } const pricedLineItem = pricingLineItems.splice(lineItemIndex, 1)[0]; lineItem.laborAmount = pricedLineItem.laborAmount; lineItem.sellingPrice = pricedLineItem.sellingPrice; lineItem.kitPrice = pricedLineItem.kitPrice; lineItem.salesTax = pricedLineItem.salesTax; }); return lineItems; } function addTaxesToPricedLineItems(pricedLineItems, taxingLineItems = []) { pricedLineItems.forEach((pricedLineItem) => { const lineItemIndex = taxingLineItems.findIndex( (taxingLineItem) => taxingLineItem.partNumber === pricedLineItem.partNumber ); if (pricedLineItem.childParts) { addTaxesToPricedLineItems(pricedLineItem.childParts, taxingLineItems); } const taxedLineItem = taxingLineItems.splice(lineItemIndex, 1)[0]; pricedLineItem.salesTax = taxedLineItem?.salesTax ?? 0; }); return pricedLineItems; } export function mapTaxedLineItemsToStoreFormat(availableLineItems, storeLineItems) { // clone the lineItems array because what we're passing in is referencing the store directly const lineItems = deepClone(storeLineItems); for (let [category, lineItemsInCategory] of Object.entries(lineItems)) { lineItemsInCategory = lineItemsInCategory ?? []; if (category == "supportingItems") { // if the category is supporting items we need to filter out the items that aren't repair chips const nonRepairChipSupportItemsLineItems = lineItemsInCategory.filter( (lineItem) => lineItem.partNumber != "WSREPAIR" ); /* Because repair chips all have the same part number but different prices based on the quantity, we have to sort the store line items and available line items by descending labor amount in order to map the tax correctly to each repair chip */ // get the supporting items that ARE repair chips and sort them by descending labor amount let repairChipLineItems = lineItemsInCategory.filter( (lineItem) => lineItem.partNumber == "WSREPAIR" ); repairChipLineItems = repairChipLineItems.sort( (a, b) => parseFloat(b.laborAmount) - parseFloat(a.laborAmount) ); // get the supporting items from the available line items (taxed) that ARE repair chips and sort them by descending labor amount let availableRepairChipLineItems = availableLineItems.filter( (lineItem) => lineItem.partNumber == "WSREPAIR" ); availableRepairChipLineItems = availableRepairChipLineItems.sort( (a, b) => parseFloat(b.laborAmount) - parseFloat(a.laborAmount) ); // go through each one of those mapping the taxes to the correct chip for (let i = 0; i < availableRepairChipLineItems.length; i++) { repairChipLineItems[i].salesTax = availableRepairChipLineItems[i].salesTax; } // then we map the non-repair chip items based on part number for ( let lineItemIndex = 0; lineItemIndex < nonRepairChipSupportItemsLineItems.length; lineItemIndex++ ) { const availableLineItem = availableLineItems.find( (ali) => ali.partNumber == nonRepairChipSupportItemsLineItems[lineItemIndex].partNumber ); if (availableLineItem) { nonRepairChipSupportItemsLineItems[lineItemIndex].salesTax = availableLineItem.salesTax; } } // finally we splice the two arrays back into one lineItemsInCategory = nonRepairChipSupportItemsLineItems.concat(repairChipLineItems); } else { for ( let lineItemIndex = 0; lineItemIndex < lineItemsInCategory.length; lineItemIndex++ ) { const availableLineItem = availableLineItems.find( (ali) => ali.partNumber == lineItemsInCategory[lineItemIndex].partNumber ); if (availableLineItem) { lineItemsInCategory[lineItemIndex].salesTax = availableLineItem.salesTax; } } } } return lineItems; } export function getArrayOfAllLineItemsAndChildParts(lineItems) { let consolidatedLineItemsArray = []; if (lineItems.glassParts != null) consolidatedLineItemsArray = [ ...consolidatedLineItemsArray, ...getFlattenedArrayOfLineItemsWithChildParts(lineItems.glassParts), ]; if (lineItems.supportingItems != null) consolidatedLineItemsArray = [ ...consolidatedLineItemsArray, ...getFlattenedArrayOfLineItemsWithChildParts(lineItems.supportingItems), ]; if (lineItems.vaps != null) consolidatedLineItemsArray = [ ...consolidatedLineItemsArray, ...getFlattenedArrayOfLineItemsWithChildParts(lineItems.vaps), ]; if (lineItems.promos != null) consolidatedLineItemsArray = [ ...consolidatedLineItemsArray, ...getFlattenedArrayOfLineItemsWithChildParts(lineItems.promos), ]; return consolidatedLineItemsArray; } function getFlattenedArrayOfLineItemsWithChildParts(lineItems, childPartRecursiveCall = false) { let flattenedArray = []; lineItems?.forEach((lineItem) => { // this assumes childparts will never be a glass part lineItem.isChildPart = childPartRecursiveCall; flattenedArray.push(lineItem); if (lineItem.childParts) { flattenedArray = [ ...flattenedArray, ...getFlattenedArrayOfLineItemsWithChildParts(lineItem.childParts, true), ]; } }); return flattenedArray; } function getFlattenedLineItemsWithGlassPartTag(lineItems) { const nonGlassLineItems = [...(lineItems.supportingItems ?? []), ...(lineItems.vaps ?? [])]; const mappedNonGlassLineItems = nonGlassLineItems.map((lineItem) => { return { partNumber: lineItem.partNumber, partType: lineItem.partType, isGlassPart: false, }; }); const glassLineItems = [...getFlattenedArrayOfLineItemsWithChildParts(lineItems.glassParts)]; const mappedGlassLineItems = glassLineItems.map((lineItem) => { return { partNumber: lineItem.partNumber, partType: lineItem.partType, isGlassPart: lineItem.isChildPart ? false : true, }; }); return [...mappedNonGlassLineItems, ...mappedGlassLineItems]; } function buildQueryStringParameterFromArrayOfComplexObjects(arrayOfObjects, parameterName) { let queryStringParameter = ""; for (let i = 0; i < arrayOfObjects.length; i++) { for (const [key, value] of Object.entries(arrayOfObjects[i])) { if (value || value === 0) { queryStringParameter += `${parameterName}[${i}].${key}=${value}&`; } } } // Remove trailing & return queryStringParameter.slice(0, -1); } function convertGlassPieceToBackEndCompatibleFormat(glassPieces) { return glassPieces.map((glassPiece) => { return { location: glassPiece.glassLocation, name: glassPiece.glassName, }; }); } function renameGlassToReplaceAttributes(glassToReplace) { let newGlassToReplace = []; if (glassToReplace) { newGlassToReplace = glassToReplace.map((item) => { return { location: item.glassLocation, name: item.glassName }; }); } return newGlassToReplace; } function addGuidToLineItemsIfNotAlreadyThere(lineItems) { lineItems?.forEach((lineItem) => { if (!lineItem.id) { lineItem.id = crypto.randomUUID(); } if (lineItem.childParts) { addGuidToLineItemsIfNotAlreadyThere(lineItem.childParts); } }); } function syncLineItemIds(lineItemsWithoutIds, lineItemsWithIds) { if (!lineItemsWithIds || !lineItemsWithoutIds) { return; } var clonedLineItemsWithIds = deepClone(lineItemsWithIds); lineItemsWithoutIds.forEach((noId) => { var matchedLineItemIndex = -1; clonedLineItemsWithIds.forEach((withId, index) => { if (noId.partNumber === withId.partNumber && noId.partType === withId.partType) { matchedLineItemIndex = index; noId.id = withId.id; } }); if (matchedLineItemIndex > -1) { // Remove the matched line item clonedLineItemsWithIds.splice(matchedLineItemIndex, 1); } }); } function providersEqual(providerA, providerB) { return ( providerA.providerNumber === providerB.providerNumber && providerA.address?.city === providerB.address?.city && providerA.address?.state === providerB.address?.state && providerA.address?.streetAddress === providerB.address?.streetAddress && providerA.address?.zipCode === providerB.address?.zipCode ); //TODO: Change back to deepEqual once zipCodeCtu is added to saveSession. } function supportingItemsEqual(supportingItemsA, supportingItemsB) { if (typeof supportingItemsA !== typeof supportingItemsB) { return false; } if (supportingItemsA === null || supportingItemsB === null) { return supportingItemsA === supportingItemsB; } if (supportingItemsA.length != supportingItemsB.length) { return false; } const sortedA = supportingItemsA.slice().sort(); const sortedB = supportingItemsB.slice().sort(); for (let i = 0; i < sortedA.length; i++) { if ( sortedA[i].partNumber != sortedB[i].partNumber || sortedA[i].partType != sortedB[i].partType ) { return false; } } return true; } // This function will verify schedule info is still valid. // check to see if we have an appointment date on the order object. // if so, make sure it's not in the past. if in the past, clear schedule info in store. // if date not in past, then call schedule service to verify appointment is still available. async function resetScheduleIfUnavailable(context, order, pageNameToLog) { if (!order.schedule?.date) { return; } // Date string with slashes is parsed as local time, not UTC. Our date has dashes, '-'. // If you put any kind of time stamp on the date string with dashes, then it IS parsed as local time. var aptDate = new Date(order.schedule.date + "T00:00:00"); var curDate = new Date(); curDate.setHours(0, 0, 0, 0); // if appointment date is in the past, clear schedule if (aptDate.getTime() < curDate.getTime()) { context.commit(storeMutations.RESET_SCHEDULE); return; } // create date range to pass to the schedule service to see if our appointment is still available. var endRange = new Date(aptDate); endRange.setDate(aptDate.getDate() + 1); var endDay = "" + endRange.getDate(); var endMonth = "" + (endRange.getMonth() + 1); // 0 based so add 1 const endYear = endRange.getFullYear(); if (endMonth.length < 2) { endMonth = "0" + endMonth; } if (endDay.length < 2) { endDay = "0" + endDay; } const endDate = [endYear, endMonth, endDay].join("-"); let newTimeSlotsResponse; if (order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE) { newTimeSlotsResponse = await context.dispatch( storeActions.GET_MOBILE_TIME_SLOTS, { payload: { startDate: order.schedule.date, endDate: endDate, }, pageNameToLog: pageNameToLog, }, false ); if (newTimeSlotsResponse?.data.days?.length === 0) { context.commit(storeMutations.RESET_SCHEDULE); return; } var mobileRouteCodeFound = false; // if early bird fee is in supporting items then need to check the timeslot to see if offer premium is also still available if ( order.lineItem?.supportingItems?.findIndex( (item) => item.partType == PREMIUM_FEE_PART_TYPE ) ) { newTimeSlotsResponse.data.days?.forEach((day) => { day.timeSlots.forEach((ts) => { if (ts.id === order.schedule.routeCode && ts.offerPremium) { mobileRouteCodeFound = true; } }); }); } else { newTimeSlotsResponse.data.days?.forEach((day) => { day.timeSlots.forEach((ts) => { if (ts.id === order.schedule.routeCode) { mobileRouteCodeFound = true; } }); }); } if (!mobileRouteCodeFound) { context.commit(storeMutations.RESET_SCHEDULE); return; } } else { newTimeSlotsResponse = await context.dispatch( storeActions.GET_SHOP_TIME_SLOTS, { payload: { startDate: order.schedule.date, endDate: endDate, shopAppointmentType: order.serviceLocation.appointmentType, providerNumber: order.serviceLocation.provider.providerNumber, }, pageNameToLog: pageNameToLog, }, false ); if (newTimeSlotsResponse?.data.days?.length === 0) { context.commit(storeMutations.RESET_SCHEDULE); return; } var routeCodeFound = false; newTimeSlotsResponse.data.days?.forEach((day) => { day.timeSlots.forEach((ts) => { if (ts.id === order.schedule.routeCode) { routeCodeFound = true; } }); }); //reset schedule if jobMin is null because when switching from cash to insurance dynamo returns null for jobMin if (!routeCodeFound || order.schedule.jobMinMinutes == null) { context.commit(storeMutations.RESET_SCHEDULE); return; } } } function createExternalParameterDefaultState() { // create default externalParameter state const externalParameterDefaultState = { isExternalParameter: externalParameterStatus.NOT_SET, vehicle: { year: null, make: null, model: null, style: null, }, vehicleDamage: { damageType: null, isRepair: null, numberOfChips: null, }, estimate: { vinSelection: null, }, serviceZip: { emailAddress: null, zipCode: null, }, quote: { isInsurance: null, servicePackage: null, }, }; // set to session storage saveExternalParameterState(externalParameterDefaultState); } function getExternalParameterDefaultState() { const externalParameterState = window.sessionStorage.getItem("externalParameterState"); if (externalParameterState === null) { createExternalParameterDefaultState(); } return JSON.parse(window.sessionStorage.getItem("externalParameterState")); } function saveExternalParameterState(externalParameterState) { window.sessionStorage.setItem("externalParameterState", JSON.stringify(externalParameterState)); }