import { defineStore } from 'pinia'; import applicationConfig from '@/constants/application-config'; import bailoutCode from '@/constants/bailoutCode'; import bailoutMessage from '@/constants/bailoutMessage'; import coverageStatuses from '@/constants/coverage-statuses'; import coverageType from '@/constants/coverage-type'; import damageLocationsSelected from '@/constants/damage-locations-selected'; import endpoints from '@/constants/endpoints'; import { experimentSettings, experimentTriggers, experimentUniverses } from '@/constants/experiments'; import partNumberStrings from '@/constants/part-number-strings'; import partTypeStrings from '@/constants/part-type-strings'; import { paymentMethods } from '@/constants/payment-method-constants'; import { AppointmentTypeStrings } from '@/constants/schedule-constants'; import webStorageConstants from '@/constants/web-storage-constants'; import globalMethods from '@/global-methods'; import { getSessionKeyValue, getUserIdValue, deleteISSCookie, getDeviceIdValue } from '@/helpers/cookie-helper'; import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper'; import { getExperimentSettingValue, getFeatureTogglesPayloadObject } from '@/helpers/experiment-helper'; import { findLineItemIndex, getLineItemsFlattened } from '@/helpers/line-items-helper'; import { deductibleForSelectedVehicle, endorsementsForSelectedVehicle, noCoverageForSelectedVehicle, repairWaivedForSelectedVehicle } from '@/helpers/policy-vehicle-helper'; import { buildURLSearchParams, getPartNumbersListForQueryString, getTaxLineItemQueryString } from '@/helpers/querystring-helper'; import { getTopLevelGlassPartsWithRecal } from '@/helpers/recal-helper'; import { getDateForSavedSessionTimeout } from '@/helpers/session-helper'; import issPageValues from '@/router/router-constants/issPage-values'; const storeId = 'main'; function getDisplayTextForDurationLength(durationMinimum, durationMaximum) { const isLongAppointment = durationMaximum >= 120; const isDurationRange = durationMinimum !== durationMaximum; const adjustedMinimum = isLongAppointment ? durationMinimum / 60 : durationMinimum; const adjustedMaximum = isLongAppointment ? durationMaximum / 60 : durationMaximum; const durationText = isDurationRange ? `${adjustedMinimum} - ${adjustedMaximum}` : adjustedMinimum; const unitText = isLongAppointment ? 'hours' : 'minutes'; return `${durationText} ${unitText}`; } function getTimeSlotsAdditionalEventData( provisionalTriggers, zipCode, firstAvailableAppointmentDateString, shopAppointmentType ) { let numberOfDays = null; if (firstAvailableAppointmentDateString) numberOfDays = getDateDifferenceInDays(new Date(), firstAvailableAppointmentDateString); if (shopAppointmentType) return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ShopAppointmentType:${shopAppointmentType},ProvisionalTriggers:${provisionalTriggers.join(',')}`; return `FirstAvailableAppointment:${numberOfDays},Zip:${zipCode},ProvisionalTriggers:${provisionalTriggers.join(',')}`; } export const getDefaultState = () => ({ order: { vehicle: { policyVehicleId: null, year: null, make: null, model: null, style: null, carId: null, category: null, vin: null, imageUrl: null, imageVifNumber: null, imageColor: null, registration: { // TODO only licensePlate saved in save session licensePlate: null, address: null, city: null, state: null, zipCode: null, firstName: null, lastName: null }, isBigTruck: null, canSafeliteService: null }, damage: { isRepair: null, numberOfChips: null, glassToReplace: null, partQuestionAnswers: null, moldingQuestionAnswers: null, capabilityQuestionAnswers: null }, policy: { policyNumber: null, policyZipCode: null, dateOfLoss: null, damageCause: null, damageState: null, damageCity: null, isDamageGlassOnly: null, deductible: { repair: null, // numerical value; how much customer owes on deductible in repair case replace: null // numerical value; how much customer owes on deductible in replace case, }, vehicles: [], endorsements: [], endorsementQuestionAnswers: [], status: null, policyData: null }, customer: { address: { streetAddress: null, streetAddress2: null, city: null, state: null, zipCode: null }, firstName: null, lastName: null, emailAddress: null }, serviceLocation: { address: null, address2: null, city: null, state: null, zipCode: null, zipCodeCtu: null, defaultProviderNumber: null, appointmentType: null, isVehicleProtected: null, IsSafeliteProvider: null, tpaSearchRadius: null, provider: { providerNumber: null, address: { streetAddress: null, city: null, state: null, zipCode: null, zipCodeCtu: null }, companyName: null, phoneNumber: null } }, lineItems: { glassParts: null, otherParts: null, supportingItems: null, feeItems: [], vaps: null, serverData: null }, insuranceCoverage: { coverageStatus: coverageStatuses.PENDING, coverageType: coverageType.NONE, isItacOptimized: false, claimNumber: null }, payment: { parentAccountNumber: 0, nextGenSettledAmount: 0, paymentMethod: null, paypalToken: null, creditCardToken: { subscriptionId: null, expMonth: null, expYear: null, cardType: null, billToPostalCode: null, billToFirstName: null, billToLastName: null, referenceNumber: null, authCode: null, transactionId: null, transReferenceNumber: null, lastFour: null } }, contactInfo: { homePhone: null, alternativePhone: null, servicePhone: null, extension: null, requestTextUpdates: false, notesForTechnician: '' }, schedule: { date: null, startTime: null, endTime: null, routeCode: null, jobMaxMinutes: null, jobMinMinutes: null }, parentAccountNumber: null, referralNumber: null, referralDate: null, referralCorrelationId: '00000000-0000-0000-0000-000000000000', referralSequenceNumber: null, eon: null, workOrderId: null, workOrderNumber: null, settledTenderAmount: null, lockToken: null, customerPortalLoginToken: null, originalDeductible: { repair: null, replace: null }, currentDeductible: { repair: null, replace: null }, totalTaxAmount: null, waiverReasons: null, carrierPhoneNumber: null, loadedFromCookie: false, loadedFromDupeCheck: null, loadedSessionClearedPreviousData: null, availableVaps: null, visitedDuplicateCheckPage: false }, applicationUser: { experiments: [], eventBus: [], // TODO not in save session pageData: {}, savedSessionTimeout: getDateForSavedSessionTimeout(), saveSessionPromise: null, savedSessionId: '00000000-0000-0000-0000-000000000000', crmCustomerId: null, lastPageVisited: null, triggeredSiteEntry: false, // TODO not in save session duplicateOrders: [], hasSentSaveQuoteEmail: null, coverageLookupAttempts: 0 }, issConfig: { clientName: 'Generic Insurance', // this is the default and will be overriden by the client's name clientFullName: 'Generic Insurance', // this is the default and will be overriden by the client's name or client's full name. clientDisplayName: 'Generic Insurance', // this is the default and will be overridden by the client's name or client display name. clientHeader: {}, styleSheet: '', // Stylesheet used by the client. parentAccountNumber: 0, // Parent account number used by the client. billToAccountNumber: null, isCoverageEnabled: false, // Indicates if we should be calling coverage on this flow. isClaimRegistrationRequired: false, // Indicates if the claim registration call needs to be made for a client to complete coverage verification. isAuthenticated: false, // Indicates if user is authenticated or not. enableContinueFromCookie: false, // Indicates if the continue from cookie modal should appear. enableTPAFlow: false, // Indicates if the TPA flow is supported for this client. successReturnURL: null, // Client URL to return the user to upon a successfull flow completetion (order submission). failureReturnURL: null, // Client URL to return the user to when they encounter an error or bailout and are unable to complete the flow. disabledFields: { // Fields that are disabled and read only if sent over from a client. policyNumber: null, policyZipCode: null, dateOfLoss: null }, siteType: null, enableNoCompQuote: false } }); export const state = getDefaultState(); export const useMainStore = defineStore({ id: storeId, state: () => state, getters: { billToAccountNumber: (storeState) => storeState.issConfig.billToAccountNumber, hasRecalibrationPart: (storeState) => getHasRecalibrationPart(storeState), vehicle: (storeState) => storeState.order.vehicle, damage: (storeState) => storeState.order.damage, lineItems: (state) => state.order.lineItems, payment: (state) => state.order.payment, policy: (state) => state.order.policy, serviceLocation: (state) => state.order.serviceLocation, hasExactlyOneChip: () => state.order.damage.numberOfChips === 1, isPolicyVehicle: () => state.order.vehicle.policyVehicleId != null, hasWindshieldReplacement: (s) => { const { damage, lineItems } = s.order; return !damage.isRepair && (lineItems.glassParts?.some((gp) => gp.partType === partTypeStrings.WINDSHIELD) ?? false); }, hasAnyNonWindshieldGlassParts: (s) => { const { damage } = s.order; const nonWindshieldItems = damage.glassToReplace?.filter((glass) => glass.glassLocation !== damageLocationsSelected.WINDSHIELD); return !!nonWindshieldItems?.length; }, hasMoldingPart: (s) => { return s.order.lineItems.glassParts?.some((glassPart) => { return glassPart.childParts?.some((childPart) => childPart.partType === partTypeStrings.MOLDING); }); }, isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE || state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP, isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF, isInShopAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.IN_SHOP, isClaimRegistrationRequired: (state) => state.issConfig.isClaimRegistrationRequired, isClaimAlreadyRegistered: (state) => state.order.insuranceCoverage.claimNumber !== null, isBailout: (state) => state.applicationUser.pageData[issPageValues.BAILOUT_PAGE] != null, bailoutCode: (state) => state.applicationUser.pageData[issPageValues.BAILOUT_PAGE]?.bailoutCode, isPolicyLookupSuccessful: (s) => s.order.insuranceCoverage.coverageType !== coverageType.NONE, isNoComp: (s) => s.order.insuranceCoverage.coverageType === coverageType.NO_COMP, isNoCompQuoteEnabled: (s) => s.issConfig.enableNoCompQuote, isITAC: (state) => state.order.insuranceCoverage.coverageType === coverageType.ITAC, isDeductible: (state) => state.order.insuranceCoverage.coverageType === coverageType.Deductible, isUnverified: (s) => s.order.insuranceCoverage.coverageStatus !== coverageStatuses.VERIFIED, isVerified: (state) => state.order.insuranceCoverage.coverageStatus === coverageStatuses.VERIFIED, isPendingClaimRegistration: (state) => state.order.insuranceCoverage.coverageStatus === coverageStatuses.PENDING, isPayInAdvance: (state) => state.order.payment.paymentMethod != null && state.order.payment.paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE, providerNumber: (state) => state.order.serviceLocation.provider.providerNumber || state.order.serviceLocation.defaultProviderNumber, hasOemEndorsement: (state) => state.order.policy.endorsements?.indexOf('OEM Approved') !== -1 ?? false, eventBusItem: (state) => (eventCategory, eventSubCategory) => { const matchedEvent = state.applicationUser.eventBus.find(({ category, subCategory }) => category === eventCategory && subCategory === eventSubCategory); return matchedEvent?.eventValue; }, eventBus: (state) => state.applicationUser.eventBus, applicationUserObj: (state) => state.applicationUser, pageData: (state) => (page) => (page in state.applicationUser.pageData ? state.applicationUser.pageData[page] : undefined), customerData: (state) => { if (state.order.vehicle.registration.address) { const { registration } = state.order.vehicle; return { addressQuestions: { streetAddress: registration.address, city: registration.city, state: registration.state, zipCode: registration.zipCode }, firstName: registration.firstName, lastName: registration.lastName }; } const { address } = state.order.customer; return { addressQuestions: { streetAddress: address.streetAddress, city: address.city, state: address.state, zipCode: address.zipCode }, firstName: state.order.customer.firstName, lastName: state.order.customer.lastName }; }, contactInfo: (s) => ({ firstName: s.order.customer.firstName, lastName: s.order.customer.lastName, emailAddress: s.order.customer.emailAddress, homePhone: s.order.contactInfo.homePhone, alternativePhone: s.order.contactInfo.alternativePhone, servicePhone: s.order.contactInfo.servicePhone, extension: s.order.contactInfo.extension, requestTextUpdates: s.order.contactInfo.requestTextUpdates ?? false, notesForTechnician: s.order.contactInfo.notesForTechnician }), scheduleDisplayText: (s) => { const dateModel = convertDateStringToDate(s.order.schedule.date); const readableDate = dateModel?.toLocaleDateString('en-us', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }); const readableStartTime = militaryToTwelveHourTime(s.order.schedule.startTime); const readableEndTime = militaryToTwelveHourTime(s.order.schedule.endTime); const readableDuration = getDisplayTextForDurationLength( s.order.schedule.jobMinMinutes, s.order.schedule.jobMaxMinutes ); return { date: readableDate, startTime: readableStartTime, endTime: readableEndTime, duration: readableDuration }; }, experimentOrder: (s) => { const ctuToUse = (s.order.serviceLocation.appointmentType === AppointmentTypeStrings.IN_SHOP || s.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF) ? s.order.serviceLocation.provider?.address?.zipCodeCtu : s.order.serviceLocation.zipCodeCtu; return { funnelVehicleYear: s.order.vehicle.year, funnelVehicleMake: s.order.vehicle.make, funnelVehicleModel: s.order.vehicle.model, funnelVehicleStyle: s.order.vehicle.style, funnelIsRepair: s.order.damage.isRepair, funnelNumberOfChips: s.order.damage.numberOfChips, funnelCarId: s.order.vehicle.carId, funnelServiceCity: s.order.serviceLocation.city, funnelServices: s.order.serviceLocation.state, funnelServiceZipCode: s.order.serviceLocation.zipCode, funnelServiceZipCodeCtu: ctuToUse, funnelParentAccountNumber: s.order.parentAccountNumber, funnelProviderNumber: s.providerNumber, funnelIsCoverageVerified: s.isVerified, funnelHasRecalibrationPart: getHasRecalibrationPart(s), funnelSelectedMultiGlass: s.order.damage.glassToReplace?.length > 1, funnelSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(s.order.damage.glassToReplace, 'glassLocation') .includes(damageLocationsSelected.WINDSHIELD), funnelSelectedBackGlass: getNonFalseValuesOfPropertyInArrayOfObjects(s.order.damage.glassToReplace, 'glassLocation') .includes(damageLocationsSelected.REAR), funnelSelectedDriverSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(s.order.damage.glassToReplace, 'glassLocation') .includes(damageLocationsSelected.DRIVER), funnelSelectedPassengerSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(s.order.damage.glassToReplace, 'glassLocation') .includes(damageLocationsSelected.PASSENGER), funnelOrderPartNumbers: [ ...getNonFalseValuesOfPropertyInArrayOfObjects( s.order.lineItems.glassParts, 'partNumber' ), ...getNonFalseValuesOfPropertyInArrayOfObjects( s.order.lineItems.otherParts, 'partNumber' ) ], funnelOrderPartTypes: [ ...getNonFalseValuesOfPropertyInArrayOfObjects( s.order.lineItems.glassParts, 'recalibrationType' ), ...getNonFalseValuesOfPropertyInArrayOfObjects( s.order.lineItems.otherParts, 'recalibrationType' ) ] }; }, experimentSettings: (state) => state.applicationUser.experiments .filter((x) => !!x.isActive) .map((x) => x.settings) .reduce((r, c) => Object.assign(r, c), {}) ?? {}, originalDeductible: (state) => (state.order.damage.isRepair ? state.order.originalDeductible.repair : state.order.originalDeductible.replace), currentDeductible: (state) => (state.order.damage.isRepair ? state.order.currentDeductible.repair : state.order.currentDeductible.replace) }, actions: { // Content API Actions lookupVinByAddress({ licenseLastName, licenseStreetAddress, licenseZip, licenseState }) { return globalMethods.callHttpClient({ method: endpoints.LookupVinByAddress.method, endpoint: endpoints.LookupVinByAddress.url, payload: { licenseLastName, licenseStreetAddress, licenseZip, licenseState } }); }, getRouteInfo(pageName) { return globalMethods.callHttpClient({ method: endpoints.GetRouteInfo.method, endpoint: endpoints.GetRouteInfo.url(applicationConfig.APPLICATION_ABBREVIATION), payload: { pageName } }); }, getHomepageName() { return globalMethods.callHttpClient({ method: endpoints.GetHomepageInfo.method, endpoint: endpoints.GetHomepageInfo.url(applicationConfig.APPLICATION_ABBREVIATION) }); }, getPageData(pageName) { return globalMethods.callHttpClient({ method: endpoints.GetPageData.method, endpoint: endpoints.GetPageData.url(applicationConfig.APPLICATION_ABBREVIATION, pageName), payload: {} }); }, // Vehicle API Actions getVehicleYears() { return globalMethods.callHttpClient({ method: endpoints.GetVehicleYears.method, endpoint: endpoints.GetVehicleYears.url, payload: {} }); }, getVehicleMakes() { return globalMethods.callHttpClient({ method: endpoints.GetVehicleMakes.method, endpoint: endpoints.GetVehicleMakes.url + this.order.vehicle.year, payload: {} }); }, getVehicleModels() { const encodedMake = encodeURIComponent(this.order.vehicle.make); return globalMethods.callHttpClient({ method: endpoints.GetVehicleModels.method, endpoint: `${endpoints.GetVehicleModels.url}/${this.order.vehicle.year}/${encodedMake}`, payload: {} }); }, getVehicleStyles() { const encodedMake = encodeURIComponent(this.order.vehicle.make); const encodedModel = encodeURIComponent(this.order.vehicle.model); return globalMethods.callHttpClient({ method: endpoints.GetVehicleStyles.method, endpoint: `${endpoints.GetVehicleStyles.url}/${this.order.vehicle.year}/${encodedMake}/${encodedModel}`, payload: {} }); }, getDamageOptions(carId) { return globalMethods.callHttpClient({ method: endpoints.GetDamageOptions.method, endpoint: `${endpoints.GetDamageOptions.url}/${carId}`, payload: {} }); }, getIsVinbyAddressPermissible() { try { const response = globalMethods.callHttpClient({ method: endpoints.IsVinbyAddressPermissible.method, endpoint: `${endpoints.IsVinbyAddressPermissible.url}?state=${this.order.customer.address.state}`, payload: {} }); return response; } catch (responseError) { return { error: { status: responseError.status } }; } }, async getCoveragePolicyInfo() { const { order, issConfig, applicationUser } = this; const { policy } = order; if (!issConfig.isCoverageEnabled || applicationUser.coverageLookupAttempts > 10) { this.updateCoverageType(coverageType.NONE); return Promise.resolve(); } this.applicationUser.coverageAttempts += 1; console.log(`Coverage lookup attempt #${this.applicationUser.coverageAttempts}. Max attempts allowed: 10.`); try { const response = await globalMethods.callHttpClient({ method: endpoints.CoveragePolicyInfo.method, endpoint: endpoints.CoveragePolicyInfo.url, payload: { accountNumber: order.parentAccountNumber?.toString(), policyNumber: policy.policyNumber, dateOfLoss: policy.dateOfLoss, zipCode: policy.policyZipCode, referralCorrelationId: order.referralCorrelationId } }); const responsePolicy = response?.data?.policies?.[0]; if (responsePolicy) { this.updateCoverageType(coverageType.Deductible); const insured = responsePolicy.insureds?.[0]; // populate parent account number if (response.data.accountNumber) { order.parentAccountNumber = parseInt(response.data.accountNumber, 10); } // populate policy holder details from policy lookup order.customer.address.streetAddress = insured?.address; order.customer.address.city = insured?.city; order.customer.address.state = insured?.state; order.customer.address.zipCode = insured?.zipCode?.toString(); order.customer.firstName = insured?.firstName; order.customer.lastName = insured?.lastName; // populate additional fields order.policy.policyData = responsePolicy.policyData; // populate vehicles order.policy.vehicles = responsePolicy.vehicles ?? []; } else { this.updateCoverageType(coverageType.NONE); } return Promise.resolve(); } catch (e) { this.updateCoverageType(coverageType.NONE); return Promise.reject(e); } }, clearDuplicateOrders() { this.applicationUser.duplicateOrders = []; }, updateDuplicateCheckVisited(visited) { this.order.visitedDuplicateCheckPage = visited; }, updateCoverageStatus(status) { this.order.insuranceCoverage.coverageStatus = status; }, updateCoverageType(type) { this.order.insuranceCoverage.coverageType = type; }, updateIsItacOptimized(isItacOptimized) { this.order.insuranceCoverage.isItacOptimized = isItacOptimized || false; }, registerClaim() { const nonNumberCharRegex = /[^0-9]/g; const { order, isITAC } = this; return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.RegisterClaim.method, endpoint: endpoints.RegisterClaim.url, payload: { referralCorrelationId: this.order.referralCorrelationId, accountNumber: this.order.parentAccountNumber?.toString() ?? '', policyData: this.order.policy.policyData, isItac: isITAC, insured: { firstName: this.order.customer.firstName, lastName: this.order.customer.lastName, address: { addressLine1: this.order.customer.address.streetAddress, addressLine2: this.order.customer.address.streetAddress2, city: this.order.customer.address.city, state: this.order.customer.address.state, zipCode: this.order.customer.address.zipCode, country: 'US' // TODO set from store }, homePhone: { number: this.contactInfo.homePhone?.replaceAll(nonNumberCharRegex, '') ?? '' } }, driver: { firstName: this.order.customer.firstName, lastName: this.order.customer.lastName }, caller: { homePhone: {} }, policyInfo: { policyNumber: this.order.policy.policyNumber, safelitePolicy: { policies: [] }, actualDeductible: this.currentDeductible.toString() ?? '' }, lossInfo: { dateOfLoss: this.order.policy.dateOfLoss, location: { city: this.order.policy.damageCity, state: this.order.policy.damageState, country: 'US' // TODO set from store }, vehicle: { id: this.order.vehicle.policyVehicleId?.toString() ?? '', year: this.order.vehicle.year?.toString() ?? '', make: this.order.vehicle.make, model: this.order.vehicle.model, vin: this.order.vehicle.vin }, cause: this.order.policy.damageCause, damageDescription: this.order.policy.damageCause } } }).then((response) => { this.order.insuranceCoverage.claimNumber = response.data.claimNumber; if (response.data.isSuccess) { this.updateCoverageStatus(coverageStatuses.VERIFIED); } else { this.updateCoverageStatus(coverageStatuses.NO_COVERAGE); } return resolve(response); }, (error) => { this.updateCoverageStatus(coverageStatuses.NO_COVERAGE); this.order.insuranceCoverage.claimNumber = null; return reject(error); }); }); }, getFinalDeductible() { const endorsementAnswersForPayload = []; const endorsementAnswers = this.order.policy.endorsementQuestionAnswers; if (endorsementAnswers) { endorsementAnswers.forEach((endorsement) => { if (endorsement.selectedAnswer === 'Yes') { endorsementAnswersForPayload.push(endorsement.endorsementName); } }); } const manualGlassNamesArray = []; const glassInformation = this.order.damage.glassToReplace; glassInformation?.forEach((glassPiece) => { manualGlassNamesArray.push(glassPiece?.glassLocation?.toUpperCase()); }); return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.FinalDeductible.method, endpoint: endpoints.FinalDeductible.url, payload: { referralCorrelationId: this.order.referralCorrelationId, accountNumber: this.order.parentAccountNumber?.toString() ?? '', endorsements: endorsementAnswersForPayload, manualGlassNames: manualGlassNamesArray, policyState: this.order.customer.address.state, status: this.order.policy.status, originalDeductible: this.originalDeductible, currentDeductible: this.currentDeductible, noCoverage: false, isRepair: this.order.damage.isRepair, policyNumber: this.order.policy.policyNumber, insuredFirstName: this.order.customer.firstName, insuredLastName: this.order.customer.lastName, insuredZipCode: this.order.customer.address.zipCode, policyVehicleId: this.order.vehicle.policyVehicleId?.toString() ?? '', vehicleVin: this.order.vehicle.vin, policyData: this.order.policy.policyData, isItac: this.isITAC } }).then((r) => { this.order.policy.policyData = r.data.policyData; this.updateDeductible(r.data); return resolve(r); }).catch((error) => reject(error)); }); }, getDuplicateReferrals() { const params = new URLSearchParams({ parentAccountNumber: this.order.parentAccountNumber, customerPhoneNumber: this.order.contactInfo.servicePhone, policyNumber: this.order.policy.policyNumber, emailAddress: this.order.customer.emailAddress, dateOfLoss: this.order.policy.dateOfLoss }); return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.DuplicateSearch.method, endpoint: `${endpoints.DuplicateSearch.url}?${params.toString()}` }).then((r) => { this.applicationUser.duplicateOrders = r.data ?? []; return resolve(r.data); }).catch((error) => { this.applicationUser.duplicateOrders = []; return reject(error); }); }); }, async lookupVinByPlate(licensePlate, licenseState) { try { const response = await globalMethods.callHttpClient({ method: endpoints.LookupVinByPlate.method, endpoint: endpoints.LookupVinByPlate.url, payload: { licensePlate, licenseState } }); return response; } catch (responseError) { return { error: { status: responseError.status } }; } }, // PartsOrQuestions API Actions async getPartsOrQuestions() { this.resetPartsAndDependencies(); const { vehicle } = this; const { damage } = this; const { order } = this; const { carId } = vehicle; const glassArray = damage.glassToReplace; const zipCode = vehicle.registration.zipCode ? vehicle.registration.zipCode : order.customer.address.zipCode; const { vin } = vehicle; // 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, glassPieces: glassArrayForPayload, zip: zipCode, vin, oemEndorsementFlag: this.hasOemEndorsement } }); // Flatten location and name properties response.data.partsOrQuestions = convertGlassPieceNamingFromApi(response.data.partsOrQuestions); return response; }, async getParts() { const { vehicle } = this.order; const { damage } = this.order; const { order } = this; const { carId } = vehicle; const glassArray = damage.glassToReplace; const resultsArray = damage.partQuestionAnswers; const zipCode = vehicle.registration.zipCode ? vehicle.registration.zipCode : order.customer.address.zipCode; const { vin } = vehicle; // 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, glassPieces: glassArrayForPayload, answerResults: resultsArrayForPayload, zip: zipCode, vin, oemEndorsementFlag: this.hasOemEndorsement } }); // Flatten location and name properties response.data.glassPieceParts = convertGlassPieceNamingFromApi(response.data.glassPieceParts); return response; }, getCapabilityQuestions(carId, partNumber) { return globalMethods.callHttpClient({ method: endpoints.GetCapabilityQuestions.method, endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}` }); }, async updatePartFromCapabilityQuestionAnswer(part, capabilityQuestionAnswersForPart) { return (await globalMethods.callHttpClient({ method: endpoints.GetPartFromCapabilityAnswer.method, endpoint: endpoints.GetPartFromCapabilityAnswer.url, payload: { part, capabilityAnswerResults: capabilityQuestionAnswersForPart } })).data[0]; }, getMobilePremiumFee() { const damageType = this.damage.isRepair ? 'Repair' : 'Replace'; const paymentType = 'Insurance'; return globalMethods.callHttpClient({ method: endpoints.GetMobilePremiumFee.method, endpoint: `${endpoints.GetMobilePremiumFee.url}/${paymentType}/${damageType}`, logApiCall: true }); }, getMobileTimeSlots(startDate, endDate, zipCodeOverride = null) { const { order } = this; const { vehicle } = this.order; let lineItems = [ ...(order.lineItems.supportingItems ?? []), ...(order.lineItems.vaps ?? []), ...(order.lineItems.glassParts ?? []) ]; lineItems = getLineItemsFlattened(lineItems); lineItems = lineItems.map((lineItem) => ({ partNumber: lineItem.partNumber, partType: lineItem.partType })); const glassPieces = order.damage.glassToReplace ? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace) : []; const payload = { startDate, endDate, applicationName: applicationConfig.APPLICATION_NAME, billToAccountNumber: this.billToAccountNumber, parentAccountNumber: order.parentAccountNumber, // this.payment.parentAccountNumber, carId: vehicle.carId, lineItems, glassPieces, eon: order.eon, coverage: { status: '', deductible: 0, additionalAuthFlag: '' }, partSelection: { hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length, hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length, hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length, hasManuallySelectedParts: !!this.applicationUser.pageData['vehicle-parts']?.partsOrQuestions .length }, vehicle: { year: vehicle.year, make: vehicle.make, model: vehicle.model, style: vehicle.style, vin: vehicle.vin ?? '' }, zipCode: zipCodeOverride ?? order.serviceLocation.zipCode }; return globalMethods.callHttpClient({ method: endpoints.GetMobileTimeSlots.method, endpoint: endpoints.GetMobileTimeSlots.url, payload, logApiCall: true, additionalSuccessEventDataHandler: (response) => getTimeSlotsAdditionalEventData( response.data.provisionalTriggers, zipCodeOverride ?? order.serviceLocation.zipCode, response.data.days?.[0]?.date ) }); }, getShopTimeSlots(startDate, endDate, shopAppointmentType, providerNumber) { const { order } = this; const { vehicle } = this.order; let lineItems = [ ...(order.lineItems.supportingItems ?? []), ...(order.lineItems.vaps ?? []), ...(order.lineItems.glassParts ?? []) ]; lineItems = getLineItemsFlattened(lineItems); lineItems = lineItems.map((lineItem) => ({ partNumber: lineItem.partNumber, partType: lineItem.partType })); const glassPieces = order.damage.glassToReplace ? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace) : []; const payload = { providerNumber, startDate, endDate, shopAppointmentType: (shopAppointmentType === AppointmentTypeStrings.IN_SHOP || shopAppointmentType === AppointmentTypeStrings.DROP_OFF) ? 'InShopOrDropoff' : shopAppointmentType, applicationName: applicationConfig.APPLICATION_NAME, billToAccountNumber: this.billToAccountNumber, parentAccountNumber: this.order.parentAccountNumber, // this.payment.parentAccountNumber, carId: vehicle.carId, lineItems, glassPieces, eon: order.eon, coverage: { status: '', deductible: 0, additionalAuthFlag: '' }, partSelection: { hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length, hasAnsweredMoldingQuestions: !!order.damage.moldingQuestionAnswers?.length, hasAnsweredCapabilityQuestions: !!order.damage.capabilityQuestionAnswers?.length, hasManuallySelectedParts: !!this.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, additionalSuccessEventDataHandler: (response) => provisionalTriggersToString(response.data.provisionalTriggers) }); }, async getWipers() { const { carId } = this.order.vehicle; const serviceZipCode = this.order.serviceLocation.zipCode; return globalMethods .callHttpClient({ method: endpoints.GetWipers.method, endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}` }) .catch((error) => { // The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow console.error(error); return []; }); }, async getRainDefense() { return globalMethods .callHttpClient({ method: endpoints.GetRainDefense.method, endpoint: `${endpoints.GetRainDefense.url}` }) .catch((error) => { // The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow console.error(error); return []; }); }, getSafeliteProviders(zipCode, radius = 100) { return this.getProviders(zipCode, radius, true) }, getTpaAndSafeliteProviders(zipCode, provderNameSearchString = "") { const { parentAccountNumber } = this.order; const carId = this.order.vehicle.carId; const damageType = this.damage.isRepair ? 'Repair' : 'Install'; const parts = getLineItemsFlattened(this.order.lineItems.glassParts); const partNumbers = parts.map((part) => part.partNumber).join(','); let url = `${endpoints.GetTpaAndSafeliteProviders.url}/${zipCode}?accountNumber=${parentAccountNumber}&carId=${carId}&damageType=${damageType}&partNumbers=${partNumbers}`; if (provderNameSearchString) { url += `&providerNameSearchString=${provderNameSearchString}`; } return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.GetTpaAndSafeliteProviders.method, endpoint: url }).then((response) => resolve(response), (error) => reject(error)); }); }, getProviders(zipcode, radius, safeliteOnly) { const { carId, isBigTruck } = this.order.vehicle; const damageType = this.damage.isRepair ? 'Repair' : 'Replace'; const { parentAccountNumber } = this.order; const partsWithRecal = getTopLevelGlassPartsWithRecal(this.order.lineItems.glassParts); const windshieldPartWithRecal = partsWithRecal?.length > 0 ? partsWithRecal[0] : null; return globalMethods.callHttpClient({ method: endpoints.GetProviders.method, endpoint: endpoints.GetProviders.url( zipcode, damageType, radius, parentAccountNumber, safeliteOnly, carId, windshieldPartWithRecal?.partNumber, isBigTruck ) }); }, getCarrierAccountInfo() { return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.GetAccountInfo.method, endpoint: endpoints.GetAccountInfo.url + this.order.parentAccountNumber }).then((response) => { this.order.carrierPhoneNumber = response.data.phoneNumber; return resolve(response.data); }).catch((error) => reject(error)); }); }, async getRecalParts() { const { glassParts } = this.lineItems; const { carId } = this.vehicle; const { parentAccountNumber, referralSequenceNumber } = this.order; const { zipCode } = this.order.serviceLocation; if (glassParts && glassParts.length > 0) { const recalPromises = []; glassParts.forEach((glassPart) => { if (glassPart.requiresRecalibration) { const partNumberChecked = glassPart.partNumber; recalPromises.push(globalMethods .callHttpClient({ method: endpoints.GetRecalParts.method, endpoint: endpoints.GetRecalParts.url( carId, partNumberChecked, glassPart.recalibrationType, parentAccountNumber, zipCode, applicationConfig.APPLICATION_NAME, referralSequenceNumber ) }) .then((response) => { const recalResponse = response.data; if (recalResponse && recalResponse.recalibrationParts && recalResponse.recalibrationParts.length > 0) { this.addGlassPartRecalibrationInfo(partNumberChecked, recalResponse.recalibrationParts[0]); } })); } }); await Promise.allSettled(recalPromises); } }, addGlassPartRecalibrationInfo(partNumber, recalPartInformation) { const glassPart = this.lineItems.glassParts.find((gp) => gp.partNumber === partNumber); if (glassPart) { const recalChildPart = glassPart.childParts?.find((cp) => cp.partNumber === recalPartInformation.partNumber); if (!recalChildPart) { if (!Array.isArray(glassPart.childParts) || !glassPart.childParts.length) { glassPart.childParts = []; } glassPart.childParts.push(recalPartInformation); } } }, async getGlassFees() { const { insuranceCoverage, vehicle } = this.order; const { glassParts } = this.lineItems; const { isRepair } = this.damage; const { defaultProviderNumber, provider, zipCode } = this.order.serviceLocation; const damageType = isRepair ? 'Repair' : 'Install'; const facilityType = this.isMobileAppointment ? 'Mobile' : 'InShop'; const providerToUse = provider?.providerNumber ?? defaultProviderNumber; const partNumberListQueryString = getPartNumbersListForQueryString(glassParts, 'PartNumbers'); const params = new URLSearchParams({ serviceType: damageType, facilityType, parentAccountNumber: this.order.parentAccountNumber, billToAccountNumber: this.billToAccountNumber, isPremiumAppointment: false, isItacOptimized: insuranceCoverage.isItacOptimized, zipCode, coverageStatus: coverageStatuses.mapToApi(insuranceCoverage.coverageStatus), coverageType: coverageType.mapToApi(insuranceCoverage.coverageType), providerNumber: providerToUse, carId: vehicle.carId }); return globalMethods.callHttpClient({ method: endpoints.GetGlassFees.method, endpoint: `${endpoints.GetGlassFees.url}?${params.toString()}${partNumberListQueryString}` }); }, async getSupportingItems() { const { glassParts } = this.lineItems; const { carId } = this.vehicle; const { isRepair, numberOfChips } = this.damage; return globalMethods .callHttpClient({ method: endpoints.GetSupportingItems.method, endpoint: endpoints.GetSupportingItems.url, payload: { carId, damageType: isRepair ? 'Repair' : 'Replace', parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, parts: glassParts ?? [], numberOfRepairChips: isRepair ? numberOfChips : 0 } }); }, async getITACPriceOrderItems(availableLineItems) { const { policy, vehicle, contactInfo, serviceLocation, insuranceCoverage } = this.order; const response = await globalMethods .callHttpClient({ method: endpoints.GetITACPriceOrderItems.method, endpoint: endpoints.GetITACPriceOrderItems.url, payload: { lineItems: getLineItemsFlattened(availableLineItems), ServerData: this.order.lineItems.serverData, Customer: { PhoneNumber: contactInfo.servicePhone, State: policy.damageState || this.order.customer.address.state, ZipCode: policy.policyZipCode }, Account: { ParentAccountNumber: this.order.parentAccountNumber, LineOfBusiness: 'PERSONAL' }, Provider: { ProviderNumber: this.providerNumber, ProviderCtuNumber: serviceLocation.zipCodeCtu, ProviderState: serviceLocation.state }, Vehicle: { CarId: vehicle.carId, Year: vehicle.year, Make: vehicle.make, Model: vehicle.model }, Insurance: { Deductible: this.currentDeductible ?? 0, PolicyNumber: policy.policyNumber, CoverageStatus: insuranceCoverage.coverageStatus, CoverageType: insuranceCoverage.coverageType }, Order: { Eon: this.order.eon, ReferralNumber: this.order.referralNumber, ReferralSequenceNumber: this.order.referralSequenceNumber, ReferralDate: `${this.order.referralDate}Z`, ServiceZipCode: serviceLocation.zipCode, IsReplacement: !this.isRepair, IsOEMRequest: this.hasOemEndorsement } } }).catch((error) => { console.error(error); throw error; }); const { lineItems, serverData, isItac, primaryBillToNumber, partsWerePriced, isItacOptimized } = response.data; if (serverData) { this.order.lineItems.serverData = serverData; } if (partsWerePriced) { this.updateIsItacOptimized(isItacOptimized); if (isItac) { // if the ITAC Pricing API call returns isItac = true then we should switch to ITAC coverage type this.updateCoverageType(coverageType.ITAC); } else if (this.isITAC) { // If the ITAC pricing API call returns isItac = false, and we are currently ITAC in the store then we should switch to deductible coverage type this.updateCoverageType(coverageType.Deductible); } } if (primaryBillToNumber && primaryBillToNumber.length !== 0) { this.issConfig.billToAccountNumber = primaryBillToNumber; } else { await this.getBillToInfo(); } if (lineItems) { const retAvailableLineItems = addPricesToLineItems(availableLineItems, lineItems); return retAvailableLineItems; } return availableLineItems; }, async getCombinedQuote(availableLineItems) { if (availableLineItems && availableLineItems.length > 0) { const { vehicle, serviceLocation, policy, eon, referralNumber, referralDate, referralSequenceNumber, lineItems } = this.order; const availableLineItemsFiltered = availableLineItems.filter((lineItem) => !!(lineItem.partNumber)); const lineItemsWithOnlyPartNumbers = availableLineItemsFiltered.map((lineItem) => ({ partNumber: lineItem.partNumber })); const payload = { ParentAccountNumber: this.order.parentAccountNumber, BillToAccountNumber: this.billToAccountNumber, ProviderNumber: this.providerNumber, CarId: vehicle.carId, Make: vehicle.make, Model: vehicle.model, Year: vehicle.year, EON: eon, ZipCode: policy.policyZipCode, State: this.order.customer.address.state, ReferralNumber: referralNumber, ReferralDate: referralDate, ReferralSequenceNumber: referralSequenceNumber, ServiceZipCode: serviceLocation.zipCode, IsReplacement: !this.isRepair, ServerData: lineItems.serverData, LineItems: lineItemsWithOnlyPartNumbers, FeatureToggles: getFeatureTogglesPayloadObject(this.experimentSettings) }; const response = await globalMethods .callHttpClient({ method: endpoints.GetCombinedQuote.method, endpoint: endpoints.GetCombinedQuote.url, payload }) .catch((error) => { console.error(error); return []; }); const { lineItems: pricedLinedItems, serverData } = response.data; if (serverData) { this.order.lineItems.serverData = serverData; } if (pricedLinedItems) { return addPricesToLineItems(availableLineItems, pricedLinedItems); } return availableLineItems; } return []; }, getMobileFeePart() { const { vehicle, insuranceCoverage } = this.order; const params = new URLSearchParams({ serviceType: this.damage.isRepair ? 'Repair' : 'Install', facilityType: 'Mobile', parentAccountNumber: this.order.parentAccountNumber, billToAccountNumber: this.billToAccountNumber, isItacOptimized: insuranceCoverage.isItacOptimized, providerNumber: this.providerNumber, carId: vehicle.carId, coverageStatus: coverageStatuses.mapToApi(insuranceCoverage.coverageStatus), coverageType: coverageType.mapToApi(insuranceCoverage.coverageType) }); return globalMethods.callHttpClient({ method: endpoints.GetMobileFeePart.method, endpoint: `${endpoints.GetMobileFeePart.url}?${params.toString()}` }); }, getServiceabilityDetails({ serviceZipCode }) { const { vehicle, damage, parentAccountNumber, referralSequenceNumber, lineItems } = this.order; const { carId } = vehicle; const glassArray = convertGlassPieceNamingForApi(damage.glassToReplace); const lineItemParts = [...(lineItems.glassParts || []), ...(lineItems.supportingItems || [])].map((part) => ({ partNumber: part.partNumber, recalibrationType: part.recalibrationType })); const params = buildURLSearchParams({ applicationName: applicationConfig.APPLICATION_NAME, parentAccountNumber, referralSequenceNumber, zip: serviceZipCode, carId, glassPieces: glassArray, lineItems: lineItemParts }); return globalMethods.callHttpClient({ method: endpoints.GetServiceabilityDetails.method, endpoint: `${endpoints.GetServiceabilityDetails.url}?${params.toString()}` }); }, lookupVehicleByVin(vin) { return globalMethods.callHttpClient({ method: endpoints.LookupVehicleByVin.method, endpoint: endpoints.LookupVehicleByVin.url, payload: { vin } }); }, async setVehicle() { const encodedMake = encodeURIComponent(this.order.vehicle.make); const encodedModel = encodeURIComponent(this.order.vehicle.model); const encodedStyle = encodeURIComponent(this.order.vehicle.style); const response = await globalMethods .callHttpClient({ method: endpoints.GetVehicle.method, endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${encodedMake}/${encodedModel}/${encodedStyle}`, payload: {} }); this.updateVehicle(response.data); return response; }, setSaveSessionInfo(response) { this.order.referralNumber = response.referralNumber; this.order.referralSequenceNumber = response.referralSequenceNumber; this.order.referralDate = response.referralDate; this.order.referralCorrelationId = response.referralCorrelationId; this.order.eon = response.eon; this.order.workOrderNumber = response.workOrderNumber; this.order.settledTenderAmount = response.settledTenderAmount; this.order.lockToken = response.lockToken; this.order.customerPortalLoginToken = response.customerPortalLoginToken; this.applicationUser.savedSessionId = response.savedSessionId; this.applicationUser.crmCustomerId = response.crmCustomerId.toString(); }, saveSession({ submitAfterSave, createWorkOrderNumberForPIA }) { const { vehicle, damage, policy, customer, contactInfo, payment, lineItems, serviceLocation, schedule, insuranceCoverage } = this.order; // We don't want to save the session for a loaded session until the car ID is set if (this.order.loadedFromDupeCheck && !vehicle.carId) { return Promise.resolve(null); } if (this.hasSubmittedOrder()) { return Promise.resolve(null); } const loadedFromDupeCheck = !!(this.order.loadedFromDupeCheck && !this.order.loadedSessionClearedPreviousData); const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); const shouldClearOnSubmit = this.isVerified && this.isDeductible; const payloadGlassParts = setClearOnSubmit(lineItems.glassParts, shouldClearOnSubmit); const payloadSupportingItems = setClearOnSubmit(lineItems.supportingItems, shouldClearOnSubmit); const payloadVapsItems = setClearOnSubmit(lineItems.vaps, shouldClearOnSubmit); const payloadFeeItems = setClearOnSubmit(lineItems.feeItems, shouldClearOnSubmit); const payload = { applicationUser: { crmCustomerId: this.applicationUser.crmCustomerId, experiments: this.applicationUser.experiments, lastPage: this.applicationUser.lastPageVisited, pageData: this.applicationUser.pageData, savedSessionId: this.applicationUser.savedSessionId }, vehicle: { year: vehicle.year, make: vehicle.make, model: vehicle.model, style: vehicle.style, vin: vehicle.vin, carId: vehicle.carId, licensePlateNumber: vehicle.registration?.licensePlate }, damage: { numberOfChips: damage.numberOfChips, glassToReplace: newGlassToReplace, isRepair: damage.isRepair, partQuestionAnswers: damage.partQuestionAnswers, moldingQuestionAnswers: damage.moldingQuestionAnswers, capabilityQuestionAnswers: damage.capabilityQuestionAnswers, dateOfLoss: policy.dateOfLoss, damageCause: policy.damageCause, damageState: policy.damageState, damageCity: policy.damageCity, isDamageGlassOnly: policy.isDamageGlassOnly }, policy: { policyHolder: { policyFirstName: customer.firstName, policyLastName: customer.lastName, policyPhoneNumber: contactInfo.servicePhone, policyEmail: customer.emailAddress, policyState: customer.address.state }, policyNumber: policy.policyNumber, policyZipCode: policy.policyZipCode, originalDeductible: this.originalDeductible, currentDeductible: this.currentDeductible, OemEndorsement: this.hasOemEndorsement, noCoverage: this.isNoComp, isItac: this.isITAC }, customer: { address: { streetAddress: customer.address?.streetAddress, streetAddress2: customer.address?.streetAddress2, city: customer.address?.city, state: customer.address?.state, zipCode: customer.address?.zipCode?.toString() }, emailAddress: customer.emailAddress, firstName: customer.firstName, lastName: customer.lastName, homePhone: contactInfo.extension && contactInfo.homePhone ? contactInfo.homePhone + contactInfo.extension : contactInfo.homePhone, servicePhone: contactInfo.servicePhone, alternativePhone: contactInfo.alternativePhone, isSmsOptIn: contactInfo.requestTextUpdates ?? false }, lineItems: { glassParts: payloadGlassParts, serverData: lineItems.serverData, supportingItems: [...payloadSupportingItems, ...payloadFeeItems], vaps: payloadVapsItems }, insuranceCoverage: { coverageType: insuranceCoverage.coverageType, coverageStatus: insuranceCoverage.coverageStatus, claimNumber: insuranceCoverage.claimNumber }, payment: { parentAccountNumber: this.order.parentAccountNumber ?? this.issConfig.parentAccountNumber, billToAccountNumber: this.billToAccountNumber, paypalToken: payment.paypalToken, paymentMethod: payment.paymentMethod === paymentMethods.PayNow ? null : payment.paymentMethod, nextGenSettledAmount: payment.nextGenSettledAmount, CCToken: payment.creditCardToken }, serviceLocation: { address: { streetAddress: serviceLocation.address, city: serviceLocation.city, state: serviceLocation.state, zipCode: serviceLocation.zipCode, zipCodeCtu: serviceLocation.zipCodeCtu }, appointmentType: (serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE || serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) ? AppointmentTypeStrings.MOBILE : serviceLocation.appointmentType, isVehicleProtected: serviceLocation.isVehicleProtected, provider: { IsSafeliteProvider: serviceLocation?.IsSafeliteProvider, providerNumber: this.providerNumber, address: { streetAddress: serviceLocation.provider?.address?.streetAddress, city: serviceLocation.provider?.address?.city, state: serviceLocation.provider?.address?.state, zipCode: serviceLocation.provider?.address?.zipCode, zipCodeCtu: serviceLocation.provider?.address?.zipCodeCtu } }, techNotes: contactInfo.notesForTechnician }, schedule: { date: schedule.date, startTime: schedule.startTime, endTime: schedule.endTime, routeCode: schedule.routeCode, jobMaxMinutes: schedule.jobMaxMinutes, jobMinMinutes: schedule.jobMinMinutes }, referralDate: this.order.referralDate, referralNumber: this.order.referralNumber?.toString(), referralCorrelationId: this.order.referralCorrelationId, referralSequenceNumber: this.order.referralSequenceNumber, eon: this.order.eon, submitToMainframe: !!this.order.referralNumber, createWorkOrderNumberForPIA, lockToken: this.order.lockToken, loadedFromDupeCheck, submitAfterSave: !!submitAfterSave }; return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.SaveSession.method, endpoint: endpoints.SaveSession.url, payload, additionalSuccessEventDataHandler: () => `Email provided: ${customer.emailAddress ? 'true' : 'false'}` }).then((response) => { if (loadedFromDupeCheck) { this.order.loadedSessionClearedPreviousData = true; } resolve(response); }, (error) => reject(error)); }); }, /** * @function getCookieValueByName * @param {object} payload * referralNumber: the sv2 referral's referralNumber * responseDate: the sv2 referral's referralDate or the responseDate associated with the returned duplicate-check record * parentAccountNumber: the client's parentAccountNumber associated with the sv2 referral * correlationId: the correlationId associated with the sv2 referral * @summary * Gets cookie value by name, returns empty string if not found. * @returns {object} returns the response object for the load session api, which returns the sv2 referral information */ async getReferralByPayload(payload) { return await globalMethods.callHttpClient({ method: endpoints.LoadSession.method, endpoint: endpoints.LoadSession.url, payload: { referralNumber: payload.referralNumber, referralDate: payload.responseDate, parentAccountNumber: payload.parentAccountNumber, referralCorrelationId: payload.correlationId } }); }, async loadSession(duplicate) { const { order } = this; const response = await globalMethods.callHttpClient({ method: endpoints.LoadSession.method, endpoint: endpoints.LoadSession.url, payload: { referralNumber: duplicate.referralNumber, referralDate: duplicate.referralDate, parentAccountNumber: order.parentAccountNumber, referralCorrelationId: duplicate.correlationId } }); const { data } = response; if (!data) { return; } if (data?.customer) { order.customer.firstName = data?.customer?.firstName; order.customer.lastName = data?.customer?.lastName; order.customer.emailAddress = data?.customer?.emailAddress; order.contactInfo.extension = data?.customer?.homePhone?.slice(10); order.contactInfo.homePhone = data?.customer?.homePhone?.slice(0, 10); order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; if (data?.customer?.address) { order.customer.address.streetAddress = data.customer?.address?.streetAddress; order.customer.address.streetAddress2 = data.customer?.address?.streetAddress2; order.customer.address.city = data.customer?.address?.city; order.customer.address.state = data.customer?.address?.state; order.customer.address.zipCode = data.customer?.address?.zipCode; } } if (data?.vehicle) { order.vehicle.year = data?.vehicle?.year; order.vehicle.make = data?.vehicle?.make; order.vehicle.model = data?.vehicle?.model; order.vehicle.style = data?.vehicle?.style; } if (this.isPolicyLookupSuccessful) { if (data.insuranceCoverage) { order.insuranceCoverage.coverageType = data?.insuranceCoverage?.coverageType; order.insuranceCoverage.coverageStatus = data?.insuranceCoverage?.coverageStatus; order.insuranceCoverage.claimNumber = data?.insuranceCoverage?.claimNumber; } else if (data?.payment?.insuranceCoverage) { if (data?.payment?.insuranceCoverage?.isVerified) { order.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED; } order.insuranceCoverage.claimNumber = data?.payment?.insuranceCoverage?.claimNumber; } if (order.policy.vehicles.length !== 0 && data.vehicle?.carId) { order.vehicle.registration.licensePlate = data?.vehicle?.licensePlateNumber; if (data.vehicle.vin) { const vehicle = order.policy.vehicles.find((v) => v.vin === data.vehicle.vin); if (vehicle) { const vehicleResponse = await this.lookupVehicleByVin(vehicle.vin); if (vehicleResponse) { this.updateVehicle({ ...vehicleResponse.data, policyVehicleId: vehicle.id, vin: vehicle.vin }); this.updateVehicleCoverage({ noCoverage: noCoverageForSelectedVehicle(vehicle), deductible: deductibleForSelectedVehicle(vehicle), repairWaived: repairWaivedForSelectedVehicle(vehicle), endorsements: endorsementsForSelectedVehicle(vehicle) }); } } } } } order.referralNumber = data?.referralNumber; order.referralDate = data?.referralDate; order.referralCorrelationId = data?.referralCorrelationId; order.referralSequenceNumber = data?.referralSequenceNumber; order.eon = data?.eon; order.loadedFromDupeCheck = true; order.loadedSessionClearedPreviousData = false; }, async loadSessionFromCookie(cookie) { const { order, issConfig } = this; const response = await this.getReferralByPayload(cookie); const { data } = response; if (data) { order.customer.address.streetAddress = data.customer?.address?.streetAddress; order.customer.address.streetAddress2 = data.customer?.address?.streetAddress2; order.customer.address.city = data.customer?.address?.city; order.customer.address.state = data.customer?.address?.state; order.customer.address.zipCode = data.customer?.address?.zipCode; order.customer.firstName = data?.customer?.firstName; order.customer.lastName = data?.customer?.lastName; order.customer.emailAddress = data?.customer?.emailAddress; order.contactInfo.extension = data?.customer?.homePhone?.slice(10); order.contactInfo.homePhone = data?.customer?.homePhone?.slice(0, 10); order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; if (data.insuranceCoverage) { order.insuranceCoverage.coverageType = data?.insuranceCoverage?.coverageType; order.insuranceCoverage.coverageStatus = data?.insuranceCoverage?.coverageStatus; order.insuranceCoverage.claimNumber = data?.insuranceCoverage?.claimNumber; } else if (data?.payment?.insuranceCoverage) { if (data?.payment?.insuranceCoverage?.isVerified) { order.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED; } order.insuranceCoverage.claimNumber = data?.payment?.insuranceCoverage?.claimNumber; } else { order.customer.firstName = data?.customer?.firstName; order.customer.lastName = data?.customer?.lastName; } if (order.policy.vehicles.length !== 0 && data.vehicle?.carId) { order.vehicle.registration.licensePlate = data?.vehicle?.licensePlateNumber; if (data.vehicle.vin) { const vehicle = order.policy.vehicles.find((v) => v.vin === data.vehicle.vin); if (vehicle) { const vehicleResponse = await this.lookupVehicleByVin(vehicle.vin); if (vehicleResponse) { this.updateVehicle({ ...vehicleResponse.data, policyVehicleId: vehicle.id, vin: vehicle.vin }); this.updateVehicleCoverage({ noCoverage: noCoverageForSelectedVehicle(vehicle), deductible: deductibleForSelectedVehicle(vehicle), repairWaived: repairWaivedForSelectedVehicle(vehicle), endorsements: endorsementsForSelectedVehicle(vehicle) }); } } } order.vehicle.year = data.vehicle.year; order.vehicle.make = data.vehicle.make; order.vehicle.model = data.vehicle.model; order.vehicle.style = data.vehicle.style; } order.policy.damageCause = data?.policy?.damageCause; order.policy.damageCity = data?.policy?.damageCity; order.policy.damageState = data?.policy?.damageState; order.policy.dateOfLoss = data?.policy?.dateOfLoss; order.policy.isDamageGlassOnly = data?.policy?.isDamageGlassOnly; order.policy.policyNumber = data?.policy?.policyNumber; order.policy.policyZipCode = data?.policy?.policyZipCode; order.referralNumber = data?.referralNumber; order.referralDate = data?.referralDate; order.referralCorrelationId = data?.referralCorrelationId; order.referralSequenceNumber = data?.referralSequenceNumber; order.eon = data?.eon; order.workOrderId = data?.workOrderId; order.loadedFromCookie = true; order.visitedDuplicateCheckPage = true; order.loadedSessionClearedPreviousData = false; issConfig.enableContinueFromCookie = false; this.updateIsSafeliteProvider(data?.provider?.isSafeliteProvider); } return data; }, updateCreditCardToken(token) { this.order.payment.creditCardToken.subscriptionId = token.subscriptionId; this.order.payment.creditCardToken.expMonth = token.expMonth; this.order.payment.creditCardToken.expYear = token.expYear; this.order.payment.creditCardToken.cardType = token.cardType; this.order.payment.creditCardToken.billToPostalCode = token.billToPostalCode; this.order.payment.creditCardToken.billToFirstName = token.billToFirstName; this.order.payment.creditCardToken.billToLastName = token.billToLastName; this.order.payment.creditCardToken.referenceNumber = token.referenceNumber; this.order.payment.creditCardToken.authCode = token.authCode; this.order.payment.creditCardToken.transactionId = token.transactionId; this.order.payment.creditCardToken.transReferenceNumber = token.transReferenceNumber; this.order.payment.creditCardToken.lastFour = token.lastFour; }, updatePaypalToken(token) { this.order.payment.paypalToken = token; }, setSaveSessionPromise(promise) { this.applicationUser.saveSessionPromise = promise; }, clearSaveSessionPromise() { this.applicationUser.saveSessionPromise = null; }, saveEndorsementQuestionAnswers(endorsementQuestionAnswersArray) { // if endorsement question answers have changed, reset question answers const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.policy.endorsementQuestionAnswers, 'result'); const sortedEndorsementQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(endorsementQuestionAnswersArray, 'result'); const haveEndorsementQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedEndorsementQuestionAnswersArray.length || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedEndorsementQuestionAnswersArray[i].result); if (haveEndorsementQuestionAnswersChanged) { this.updateEndorsementQuestionAnswers(null); } this.updateEndorsementQuestionAnswers(endorsementQuestionAnswersArray); }, saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) { const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort(); const isGlassToReplaceTheSame = this.order.damage.glassToReplace?.length === selectedGlassToReplace.length && this.order.damage.glassToReplace .slice() .sort() .every((obj, index) => obj.glassLocation === selectedGlassPassedInSorted[index].glassLocation && obj.glassName === selectedGlassPassedInSorted[index].glassName); const isWindshieldRepairTheSame = isWindshieldRepair === this.order.damage.isRepair; const isChipCountTheSame = selectedWindshieldChipCount === this.order.damage.numberOfChips; const isDamageChanging = !isGlassToReplaceTheSame || !isWindshieldRepairTheSame || (isWindshieldRepair && !isChipCountTheSame); if (isDamageChanging) { // Reset dependent state when changing // Was resetGlassPartsState, added dependencies for SSR-290 this.resetPartsAndDependencies(); // Save new values this.updateIsRepair(isWindshieldRepair); this.updateNumberOfChips(isWindshieldRepair ? parseInt(selectedWindshieldChipCount) : null); this.updateGlassToReplace(selectedGlassToReplace); } }, updateRegistration(registrationInfo) { this.order.vehicle.registration.licensePlate = registrationInfo?.licensePlate; this.order.vehicle.registration.address = registrationInfo?.address; this.order.vehicle.registration.city = registrationInfo?.city; this.order.vehicle.registration.state = registrationInfo?.state; this.order.vehicle.registration.zipCode = registrationInfo?.zipCode; this.order.vehicle.registration.firstName = registrationInfo?.firstName; this.order.vehicle.registration.lastName = registrationInfo?.lastName; }, updateServiceLocation(serviceLocationInfo) { this.order.serviceLocation.address = serviceLocationInfo.address ?? this.order.serviceLocation.address; this.order.serviceLocation.address2 = serviceLocationInfo.address2 ?? this.order.serviceLocation.address2; this.order.serviceLocation.city = serviceLocationInfo.city ?? this.order.serviceLocation.city; this.order.serviceLocation.state = serviceLocationInfo.state ?? this.order.serviceLocation.state; this.order.serviceLocation.zipCode = serviceLocationInfo.zipCode ?? this.order.serviceLocation.zipCode; this.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu ?? this.order.serviceLocation.zipCodeCtu; this.order.serviceLocation.appointmentType = serviceLocationInfo.appointmentType ?? this.order.serviceLocation.appointmentType; this.order.serviceLocation.isVehicleProtected = serviceLocationInfo.isVehicleProtected ?? this.order.serviceLocation.isVehicleProtected; if (serviceLocationInfo.provider) { this.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 }, companyName: serviceLocationInfo.provider?.companyName, phoneNumber: serviceLocationInfo.provider?.phoneNumber }; } this.order.serviceLocation.tpaSearchRadius = serviceLocationInfo.tpaSearchRadius; }, resetState() { Object.assign(this, getDefaultState()); }, resetRegistrationState() { this.order.vehicle.registration.licensePlate = null; this.order.vehicle.registration.address = null; this.order.vehicle.registration.city = null; this.order.vehicle.registration.state = null; this.order.vehicle.registration.zipCode = null; this.order.vehicle.registration.firstName = null; this.order.vehicle.registration.lastName = null; }, resetServiceLocationAndDependencies() { this.resetServiceLocationAppointmentType(); this.resetServiceLocationProvider(); this.resetSchedule(); }, resetServiceLocationAppointmentType() { this.order.serviceLocation.appointmentType = null; }, resetServiceLocationProvider() { this.order.serviceLocation.provider = { providerNumber: null, companyName: null, phoneNumber: null, address: { streetAddress: null, city: null, state: null, zipCode: null, zipCodeCtu: null } }; }, resetServiceLocationMobileAddress() { this.order.serviceLocation.address = null; this.order.serviceLocation.address2 = null; this.order.serviceLocation.city = null; this.order.serviceLocation.state = null; this.order.serviceLocation.isVehicleProtected = null; }, resetBailout() { this.updatePageData({ page: issPageValues.BAILOUT_PAGE, data: null }); }, resetInsurance() { this.order.insuranceCoverage.coverageStatus = coverageStatuses.PENDING; this.order.insuranceCoverage.coverageType = coverageType.NONE; this.order.insuranceCoverage.isItacOptimized = false; this.order.insuranceCoverage.claimNumber = null; }, updateGlassFees(feeData) { if (feeData == null) { this.order.lineItems.feeItems = null; return; } feeData.forEach((fee) => { if (fee.partNumber === partTypeStrings.MOBILE_FEE) { this.updateMobileFee(fee); } else if (fee.partNumber === partNumberStrings.RECYCLE_FEE) { this.updateRecycleFee(fee); } else { this.addPartNumberFeeItem(fee, fee.partNumber); } }); }, updateSupportingItems(partsData) { if (partsData == null) { this.order.lineItems.supportingItems = []; return; } // Process Recycle Fee this.updateRecycleFee(partsData.find((rf) => rf.partNumber === partNumberStrings.RECYCLE_FEE)); // Remove RecycleFee from supported items as it's saved in feeItems; this.order.lineItems.supportingItems = partsData.filter((i) => i.partNumber !== partNumberStrings.RECYCLE_FEE); }, updateVaps(partsData) { this.order.lineItems.vaps = partsData; }, updateMobileFee(fee) { const isMobileFeeHidden = getExperimentSettingValue(this.experimentSettings, experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true'; // Mobile Fee is only added for NO COMP or ITAC and is NOT hidden if (fee && this.isVerified && (this.isNoComp || this.isITAC) && !isMobileFeeHidden) { this.addPartTypeFeeItem(fee, partTypeStrings.MOBILE_FEE); } else { this.addPartTypeFeeItem(null, partTypeStrings.MOBILE_FEE); } }, updateRecycleFee(fee) { const isRecycleFeeHidden = getExperimentSettingValue(this.experimentSettings, experimentSettings.ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN) === 'true'; // Recycle Fee is only added for NO COMP or ITAC and has Windshield Replacement and is NOT hidden if (fee && this.isVerified && (this.isNoComp || this.isITAC) && this.hasWindshieldReplacement && !isRecycleFeeHidden) { this.addPartNumberFeeItem(fee, partNumberStrings.RECYCLE_FEE); } else { this.addPartNumberFeeItem(null, partNumberStrings.RECYCLE_FEE); } }, addPartNumberFeeItem(feeItem, partNumber) { this.addFeeItem(feeItem, (fi) => fi.partNumber !== partNumber); }, addPartTypeFeeItem(feeItem, partType) { this.addFeeItem(feeItem, (fi) => fi.partType !== partType); }, addFeeItem(feeItem, filter) { let { feeItems } = this.order.lineItems; // Remove all fee items with the given filter feeItems = feeItems.filter(filter); if (feeItem) { feeItems.push(feeItem); } this.order.lineItems.feeItems = feeItems; }, async setPriceAndSalesTaxForOrderLineItems() { let lineItemsToTax; if (this.isVerified && !this.isDeductible) { lineItemsToTax = [ ...(this.order.lineItems.supportingItems ?? []), ...(this.order.lineItems.glassParts ?? []), ...(this.order.lineItems.otherParts ?? []), ...(this.order.lineItems.vaps ?? []), ...(this.order.lineItems.feeItems ?? []) ]; } else { lineItemsToTax = [ ...(this.order.lineItems.vaps ?? []), ...(this.order.lineItems.feeItems ?? []) ]; } if (lineItemsToTax && lineItemsToTax.length > 0) { await this.getTaxOrderItems(lineItemsToTax); } }, updateVehicle(vehicle) { // Assuming that the method caller pass all the properties. // otherwise need to check for undefined for every property. if (this.order.vehicle.carId !== vehicle.carId || (!this.order.vehicle.vin && vehicle.vin) || (this.order.vehicle.vin && vehicle.vin && this.order.vehicle.vin !== vehicle.vin)) { this.order.vehicle.vin = vehicle.vin; } this.order.vehicle.policyVehicleId = vehicle.policyVehicleId; this.order.vehicle.carId = vehicle.carId; this.order.vehicle.category = vehicle.category; this.order.vehicle.year = vehicle.year; this.order.vehicle.make = vehicle.make; this.order.vehicle.model = vehicle.model; this.order.vehicle.style = vehicle.style; this.order.vehicle.imageUrl = vehicle.imageUrl; this.order.vehicle.imageVifNumber = vehicle.imageVifNumber; this.order.vehicle.imageColor = vehicle.imageVifColor; this.order.vehicle.isBigTruck = vehicle.isBigTruck; this.order.vehicle.canSafeliteService = vehicle.canSafeliteService; this.updateSupportingItems(null); this.updateVaps(null); }, updateVehicleCoverage(coverage) { if (coverage.noCoverage) { if (this.isNoCompQuoteEnabled) { this.updateCoverageType(coverageType.NO_COMP); } else { this.updateCoverageType(coverageType.NONE); } } else { this.updateCoverageType(coverageType.Deductible); } if (!this.isClaimRegistrationRequired) { this.updateCoverageStatus(coverageStatuses.VERIFIED); } this.order.policy.deductible.replace = coverage.deductible; this.order.policy.deductible.repair = coverage?.repairWaived ?? false ? 0 : coverage.deductible; this.order.policy.endorsements = coverage?.endorsements; this.order.originalDeductible.replace = this.order.policy.deductible.replace; this.order.currentDeductible.replace = this.order.policy.deductible.replace; this.order.originalDeductible.repair = this.order.policy.deductible.repair; this.order.currentDeductible.repair = this.order.policy.deductible.repair; }, resetOrder() { this.order.referralNumber = null; this.order.referralSequenceNumber = null; this.order.referralDate = null; this.order.referralSequenceNumber = null; this.order.workOrderId = null; this.order.workOrderNumber = null; this.order.settledTenderAmount = null; this.order.lockToken = null; this.order.eon = null; this.order.originalDeductible.repair = null; this.order.originalDeductible.replace = null; this.order.currentDeductible.repair = null; this.order.currentDeductible.replace = null; this.order.loadedFromDupeCheck = null; this.order.loadedSessionClearedPreviousData = null; this.order.availableVaps = null; this.order.carrierPhoneNumber = null; this.order.customerPortalLoginToken = null; this.order.loadedFromCookie = false; this.order.visitedDuplicateCheckPage = false; }, resetPolicy() { this.order.policy.policyNumber = null; this.order.policy.policyZipCode = null; this.order.policy.dateOfLoss = null; this.order.policy.damageCause = null; this.order.policy.damageCity = null; this.order.policy.damageState = null; this.order.policy.vehicles = []; this.order.policy.endorsements = []; this.order.policy.endorsementQuestionAnswers = []; this.order.policy.policyData = null; this.order.policy.deductible.repair = null; this.order.policy.deductible.replace = null; }, resetPayment() { this.order.payment.parentAccountNumber = 0; this.order.payment.nextGenSettledAmount = 0; this.order.payment.paymentMethod = null; this.order.payment.paypalToken = null; this.order.payment.creditCardToken.subscriptionId = null; this.order.payment.creditCardToken.expMonth = null; this.order.payment.creditCardToken.expYear = null; this.order.payment.creditCardToken.cardType = null; this.order.payment.creditCardToken.billToPostalCode = null; this.order.payment.creditCardToken.billToFirstName = null; this.order.payment.creditCardToken.billToLastName = null; this.order.payment.creditCardToken.referenceNumber = null; this.order.payment.creditCardToken.authCode = null; this.order.payment.creditCardToken.transactionId = null; this.order.payment.creditCardToken.transReferenceNumber = null; this.order.payment.creditCardToken.lastFour = null; }, resetCustomer() { this.order.customer.emailAddress = null; this.order.customer.firstName = null; this.order.customer.lastName = null; this.order.customer.address.city = null; this.order.customer.address.state = null; this.order.customer.address.zipCode = null; this.order.customer.address.streetAddress = null; this.order.customer.address.streetAddress2 = null; }, resetContactInfo() { this.order.contactInfo.homePhone = null; this.order.contactInfo.alternativePhone = null; this.order.contactInfo.servicePhone = null; this.order.contactInfo.extension = null; this.order.contactInfo.requestTextUpdates = false; this.order.contactInfo.notesForTechnician = ''; }, resetVehicleState() { this.order.vehicle.policyVehicleId = null; this.order.vehicle.year = null; this.order.vehicle.make = null; this.order.vehicle.model = null; this.order.vehicle.style = null; this.order.vehicle.carId = null; this.order.vehicle.category = null; this.order.vehicle.vin = null; this.order.vehicle.imageUrl = null; this.order.vehicle.imageVifNumber = null; this.order.vehicle.imageColor = null; this.order.vehicle.registration.licensePlate = null; this.order.vehicle.registration.state = null; this.order.vehicle.registration.address = null; this.order.vehicle.registration.city = null; this.order.vehicle.registration.zipCode = null; this.order.vehicle.registration.firstName = null; this.order.vehicle.registration.lastName = null; this.order.vehicle.isBigTruck = null; this.order.vehicle.canSafeliteService = null; if (this.isBailout && this.bailoutCode === bailoutCode.HeavyTruckVehicle) { this.resetBailout(); } }, resetGlassPartsState() { this.order.lineItems.glassParts = null; this.order.lineItems.supportingItems = []; this.order.lineItems.vaps = null; this.order.lineItems.feeItems = []; this.order.lineItems.serverData = null; this.order.damage.partQuestionAnswers = null; this.order.damage.moldingQuestionAnswers = null; this.order.damage.capabilityQuestionAnswers = null; this.applicationUser.pageData[issPageValues.PART_QUESTIONS] = null; this.applicationUser.pageData[issPageValues.VEHICLE_PARTS] = null; this.applicationUser.pageData[issPageValues.MOLDING_QUESTIONS] = null; this.applicationUser.pageData[issPageValues.CAPABILITY_QUESTIONS] = null; }, resetSchedule() { this.order.schedule.date = null; this.order.schedule.startTime = null; this.order.schedule.endTime = null; this.order.schedule.routeCode = null; this.order.schedule.jobMaxMinutes = null; this.order.schedule.jobMinMinutes = null; }, resetDamageState() { this.order.damage.isRepair = null; this.order.damage.numberOfChips = null; this.order.damage.glassToReplace = null; }, resetISSConfigState() { this.issConfig.clientName = 'Generic Insurance'; this.issConfig.clientFullName = 'Generic Insurance'; this.issConfig.clientDisplayName = 'Generic Insurance'; this.issConfig.clientHeader = {}; this.issConfig.parentAccountNumber = 0; this.issConfig.styleSheet = ''; this.issConfig.isCoverageEnabled = false; this.issConfig.isAuthenticated = false; this.issConfig.enableContinueFromCookie = false; this.issConfig.enableTPAFlow = false; this.issConfig.isClaimRegistrationRequired = false; this.issConfig.successReturnURL = null; this.issConfig.failureReturnURL = null; this.issConfig.disabledFields.policyNumber = false; this.issConfig.disabledFields.policyZipCode = false; this.issConfig.disabledFields.dateOfLoss = false; this.issConfig.siteType = null; this.issConfig.enableNoCompQuote = false; this.issConfig.billToAccountNumber = null; }, disableKeyFields() { this.issConfig.disabledFields.policyNumber = true; this.issConfig.disabledFields.policyZipCode = true; this.issConfig.disabledFields.dateOfLoss = true; }, updateVehicleYear(year) { if (this.order.vehicle.year !== year) { this.resetVehicleState(); this.resetDamageAndDependencies(); this.order.vehicle.year = year; } }, updateVehicleMake(make) { if (this.order.vehicle.make !== make) { const { year } = this.order.vehicle; this.resetVehicleState(); this.resetDamageAndDependencies(); this.order.vehicle.year = year; this.order.vehicle.make = make; } }, updateVehicleModel(model) { if (this.order.vehicle.model !== model) { const { year } = this.order.vehicle; const { make } = this.order.vehicle; this.resetVehicleState(); this.resetDamageAndDependencies(); this.order.vehicle.year = year; this.order.vehicle.make = make; this.order.vehicle.model = model; } }, updateVehicleStyle(style) { if (this.order.vehicle.style !== style) { const { year } = this.order.vehicle; const { make } = this.order.vehicle; const { model } = this.order.vehicle; this.resetVehicleState(); this.resetDamageAndDependencies(); this.order.vehicle.year = year; this.order.vehicle.make = make; this.order.vehicle.model = model; this.order.vehicle.style = style; } }, updateEndorsementQuestionAnswers(answersArray) { this.order.policy.endorsementQuestionAnswers = answersArray; }, updateIsRepair(isRepair) { this.order.damage.isRepair = isRepair; }, updateNumberOfChips(numberOfChips) { this.order.damage.numberOfChips = numberOfChips; }, updateGlassToReplace(glassToReplace) { this.order.damage.glassToReplace = glassToReplace; }, updateGlassParts(partsData) { this.order.lineItems.glassParts = partsData; }, updateMoldingQuestionAnswers(answersArray) { this.order.damage.moldingQuestionAnswers = answersArray; }, updateCapabilityQuestionAnswers(answersArray) { this.order.damage.capabilityQuestionAnswers = answersArray; }, updatePartQuestionAnswers(answersArray) { this.order.damage.partQuestionAnswers = answersArray; }, updatePageData(pageData) { this.applicationUser.pageData[pageData.page] = pageData.data; }, updatePolicyData(welcomePageModel) { this.order.policy.policyNumber = welcomePageModel?.policyNumber; this.order.policy.policyZipCode = welcomePageModel?.policyZipCode; this.order.policy.dateOfLoss = welcomePageModel?.dateOfLoss; this.order.policy.damageCause = welcomePageModel?.damageCause; this.order.policy.damageState = welcomePageModel?.damageState; this.order.policy.damageCity = welcomePageModel?.damageCity; this.order.policy.isDamageGlassOnly = welcomePageModel?.isDamageGlassOnly; this.order.serviceLocation.zipCode = welcomePageModel?.policyZipCode; this.updatePhoneNumbers({ home: welcomePageModel?.phoneNumber, service: welcomePageModel?.phoneNumber, extension: welcomePageModel?.extension }); }, updatePolicyHolderDetails(customerQuestions) { this.order.customer.address.streetAddress = customerQuestions.addressQuestions.streetAddress; this.order.customer.address.streetAddress2 = customerQuestions.addressQuestions.streetAddress2; this.order.customer.address.city = customerQuestions.addressQuestions.city; this.order.customer.address.state = customerQuestions.addressQuestions.state; this.order.customer.address.zipCode = customerQuestions.addressQuestions.zipCode; this.order.customer.firstName = customerQuestions.firstName; this.order.customer.lastName = customerQuestions.lastName; this.order.customer.emailAddress = customerQuestions.email; this.updatePhoneNumbers({ home: customerQuestions.phoneNumber, service: customerQuestions.phoneNumber, extension: customerQuestions.extension }); this.order.serviceLocation.zipCode = customerQuestions.addressQuestions.zipCode; }, updateIsSafeliteProvider(isSafelite) { this.order.serviceLocation.IsSafeliteProvider = isSafelite; }, updateDeductible(deductibleInfo) { if (this.order.damage.isRepair) { this.order.currentDeductible.repair = deductibleInfo.deductible; } else { this.order.currentDeductible.replace = deductibleInfo.deductible; } }, savePartQuestionAnswers(partQuestionAnswersArray) { // if part question answers have changed, reset subsequent question answers const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.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) { this.resetServiceLocationAndDependencies(); this.updateGlassParts(null); this.updateMoldingQuestionAnswers(null); this.updateCapabilityQuestionAnswers(null); this.updateSupportingItems(null); this.updateVaps(null); this.updatePageData({ page: issPageValues.VEHICLE_PARTS, data: null }); this.updatePageData({ page: issPageValues.MOLDING_QUESTIONS, data: null }); this.updatePageData({ page: issPageValues.CAPABILITY_QUESTIONS, data: null }); } // Save new values this.updatePartQuestionAnswers(partQuestionAnswersArray); }, saveMoldingQuestionAnswers(moldingQuestionAnswersArray) { const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.moldingQuestionAnswers, 'result'); const sortedMoldingQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(moldingQuestionAnswersArray, 'result'); const haveMoldingQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedMoldingQuestionAnswersArray.length || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedMoldingQuestionAnswersArray[i].result); if (haveMoldingQuestionAnswersChanged) { this.resetServiceLocationAndDependencies(); this.updateGlassParts(null); this.updateSupportingItems(null); this.updateCapabilityQuestionAnswers(null); this.updatePageData({ page: issPageValues.CAPABILITY_QUESTIONS, data: null }); } // Save new values this.updateMoldingQuestionAnswers(moldingQuestionAnswersArray); }, saveCapabilityQuestionAnswers(capabilityQuestionAnswersArray) { const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.capabilityQuestionAnswers, 'result'); const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswersArray, 'result'); const haveCapabilityQuestionAnswersChanged = sortedPreviousResultsArray?.length !== sortedCapabilityQuestionAnswersArray.length || !sortedPreviousResultsArray?.every((x, i) => x.result === sortedCapabilityQuestionAnswersArray[i].result); if (haveCapabilityQuestionAnswersChanged) { this.resetServiceLocationAndDependencies(); this.updateGlassParts(null); this.updateSupportingItems(null); } // Save new values this.updateCapabilityQuestionAnswers(capabilityQuestionAnswersArray); }, // Tax order actions async getTaxOrderItems(pricedLineItems) { const { order } = this; const { serviceLocation } = order; const { appointmentType } = serviceLocation; const serviceLocationCity = serviceLocation.city; const serviceLocationState = serviceLocation.state; const serviceLocationZipCode = serviceLocation.zipCode; const lineItemServerData = this.order.lineItems.serverData; const isMobileApt = appointmentType === AppointmentTypeStrings.MOBILE || appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; const retPricedLineItems = await globalMethods.callHttpClient({ method: endpoints.TaxOrderItems.method, endpoint: endpoints.TaxOrderItems.url, payload: { ParentAccountNumber: this.order.parentAccountNumber, BillToAccountNumber: this.billToAccountNumber, ProviderNumber: this.providerNumber, AppointmentType: appointmentType, PricedLineItems: getLineItemsFlattened(pricedLineItems), ServiceLocation: { City: isMobileApt ? serviceLocationCity : null, State: isMobileApt ? serviceLocationState : null, ZipCode: isMobileApt ? serviceLocationZipCode : null }, ServerData: lineItemServerData || '' } }).then((response) => { this.order.lineItems.serverData = response.data.serverData; return addTaxesToPricedLineItems(pricedLineItems, response.data.taxedLineItems); }); return retPricedLineItems; }, addEventToBus(event) { this.applicationUser.eventBus.push(event); }, removeEventFromBus(eventData) { const matchedEvent = this.applicationUser.eventBus.find(({ category, subCategory }) => category === eventData.category && subCategory === eventData.subCategory); const itemIndex = this.applicationUser.eventBus.indexOf(matchedEvent); // If the item exists, remove it. if (itemIndex > -1) { this.applicationUser.eventBus.splice(itemIndex, 1); } }, // populate initial state populateInitialState(forceReset) { if (!sessionStorage.getItem(storeId) || forceReset) { this.$state = state; } }, // Location API Actions getAlertReasonsByCtu(ctu) { return globalMethods.callHttpClient({ method: endpoints.GetAlertReasons.method, endpoint: `${endpoints.GetAlertReasons.url}/${ctu}`, payload: {}, logApiCall: true }); }, // Schedule Actions saveSchedule(scheduleInfo) { this.updateSchedule(scheduleInfo); }, updateSchedule(scheduleInfo) { if (scheduleInfo) { this.order.schedule.date = scheduleInfo.date; this.order.schedule.startTime = scheduleInfo.startTime; this.order.schedule.endTime = scheduleInfo.endTime; this.order.schedule.routeCode = scheduleInfo.routeCode; this.order.schedule.jobMaxMinutes = scheduleInfo.jobMaxMinutes; this.order.schedule.jobMinMinutes = scheduleInfo.jobMinMinutes; } }, // Analytics Actions logExperimentExposure(pageName, experiment) { return globalMethods.callHttpClient({ method: endpoints.LogExperimentExposureIfAssigned.method, endpoint: endpoints.LogExperimentExposureIfAssigned.url, payload: { experimentForLogging: { userId: getUserIdValue(), deviceId: getDeviceIdValue(), 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: getSessionKeyValue(), pageName } } }); }, logExperimentIfExists(pageName, universe) { const experiment = this.applicationUser.experiments.find((e) => e.universeName === universe); if (experiment !== undefined) { this.logExperimentExposure(pageName, experiment); } }, logPageView({ userId, sessionKey, pageName, sessionId, action, event, shouldUseSessionId, experimentsForUser }) { const payload = { userId, sessionKey, sessionId, pageName, applicationName: applicationConfig.APPLICATION_NAME, action, event, shouldUseSessionId, experimentsForUser }; return globalMethods.callHttpClient({ method: endpoints.LogPageView.method, endpoint: endpoints.LogPageView.url, payload, logApiCall: false }).then( (response) => response, (error) => { console.log(`Analytics Service Error: ${error.data}`); } ); }, logCustomEvent({ userId, sessionKey, pageName, sessionId, category, action, label, value, shouldUseSessionId, experimentsForUser }) { if (pageName == null || pageName.length === 0) { pageName = 'none'; } const payload = { userId, sessionKey, sessionId, pageName, applicationName: applicationConfig.APPLICATION_NAME, category, action, label, value, shouldUseSessionId, experimentsForUser }; return globalMethods.callHttpClient({ method: endpoints.LogCustomEvent.method, endpoint: endpoints.LogCustomEvent.url, payload, logApiCall: false }).then( (response) => response, (error) => { console.log(`Analytics Service Error: ${error.data}`); } ); }, logWelcomePageExperiments(issPage) { this.logExperimentIfExists(issPage, experimentUniverses.ISS_FEATURETOGGLE_AREFEES_HIDDEN); this.logExperimentIfExists(issPage, experimentUniverses.ISS_FEATURETOGGLE_AREFEES_OVERRIDDEN); }, initializeSession({ userId, sessionId, userAgent, referrer }) { const payload = { applicationName: applicationConfig.APPLICATION_NAME, userId, deviceId: userId, sessionId, userAgent, operatorId: 'WEB', userName: 'SafeliteISS', referrer }; return globalMethods.callHttpClient({ method: endpoints.InitializeSession.method, endpoint: endpoints.InitializeSession.url, payload, logApiCall: false }).then( (response) => response, (error) => { console.log(`Analytics Service Error: ${error.data}`); } ); }, updateLastPageVisited(lastPageVisited) { this.applicationUser.lastPageVisited = lastPageVisited; }, updateExperiments(experiments) { this.applicationUser.experiments = experiments; }, updateTriggeredSiteEntry(wasSiteEntryTriggered) { this.applicationUser.triggeredSiteEntry = wasSiteEntryTriggered; }, updateContactInfo(contactInfo) { this.order.customer.firstName = contactInfo?.firstName ?? this.order.customer.firstName; this.order.customer.lastName = contactInfo?.lastName ?? this.order.customer.lastName; this.order.customer.emailAddress = contactInfo?.emailAddress ?? this.order.customer.emailAddress; this.order.contactInfo.requestTextUpdates = contactInfo?.requestTextUpdates ?? false; this.order.contactInfo.notesForTechnician = contactInfo?.notesForTechnician ?? ''; }, updatePhoneNumbers(phoneNumbers) { const contact = this.order.contactInfo; contact.homePhone = phoneNumbers.home !== undefined ? phoneNumbers.home : contact.homePhone; contact.alternativePhone = phoneNumbers.alternative !== undefined ? phoneNumbers.alternative : contact.alternativePhone; contact.servicePhone = phoneNumbers.service !== undefined ? phoneNumbers.service : contact.servicePhone; contact.extension = phoneNumbers.extension !== undefined ? phoneNumbers.extension : contact.extension; }, GetExperimentsByUser(userId) { return globalMethods.callHttpClient({ method: endpoints.GetExperimentsByUser.method, endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`, payload: {} }); }, async runExperimentsForTrigger({ deviceId, triggerEvent, triggerValue }) { if (triggerEvent === experimentTriggers.SITE_ENTRY) { this.updateTriggeredSiteEntry(true); } const payload = { applicationName: applicationConfig.APPLICATION_NAME, deviceId, triggerEvent, triggerValue, experimentOrder: this.experimentOrder }; const response = await globalMethods.callHttpClient({ method: endpoints.RunExperimentsForTrigger.method, endpoint: endpoints.RunExperimentsForTrigger.url, payload }); this.updateExperiments(response.data.experiments); }, async validateZip({ zip }) { try { const response = await globalMethods.callHttpClient({ method: endpoints.ValidateZip.method, endpoint: endpoints.ValidateZip.url(zip) }); const zipInfo = response.data; if (zipInfo?.isValid === true) { this.order.serviceLocation.zipCodeCtu = zipInfo.zipCodeCtu; this.order.serviceLocation.defaultProviderNumber = zipInfo.providerNumber; this.order.serviceLocation.state = zipInfo.state; return Promise.resolve(zipInfo); } return Promise.reject(new Error('Invalid Zip Info')); } catch (e) { return Promise.reject(e); } }, async validateMobileZip({ zip }) { const damageType = this.order.damage.isRepair ? 'Repair' : 'Replace'; try { const response = await globalMethods.callHttpClient({ method: endpoints.ValidateZip.method, endpoint: endpoints.ValidateMobileZip.url(zip, damageType) }); const zipInfo = response.data; if (zipInfo?.isValid === true) { return Promise.resolve(zipInfo); } return Promise.reject(new Error('Invalid Zip Info')); } catch (e) { return Promise.reject(e); } }, async getBillToInfo() { const { order, issConfig } = this; try { const params = new URLSearchParams({ parentAccountNumber: order.parentAccountNumber.toString(), providerNumber: this.providerNumber, typeOfClaim: 'GLASS ONLY', lineOfBusiness: 'PERSONAL', isItac: this.isITAC }); const response = await globalMethods.callHttpClient({ method: endpoints.GetBillToInfo.method, endpoint: `${endpoints.GetBillToInfo.url}?${params.toString()}` }); const billToInfo = response.data; if (billToInfo != null) { issConfig.billToAccountNumber = billToInfo.toString(); return Promise.resolve(); } return Promise.reject(new Error('Invalid billToInfo')); } catch (e) { return Promise.reject(e); } }, async validateClientTag(clientTag) { return await globalMethods.callHttpClient({ method: endpoints.ValidateClientTag.method, endpoint: `${endpoints.ValidateClientTag.url}/${clientTag}` }); }, async validateClientSignature(clientTag, token, signature) { const payload = { clientTag, token, signature }; return await globalMethods.callHttpClient({ method: endpoints.ValidateClientSignature.method, endpoint: endpoints.ValidateClientSignature.url, payload }); }, saveServiceLocation(serviceLocationInfo) { this.updateServiceLocation(serviceLocationInfo); }, saveRegistrationAddressLookup({ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) { // Reset dependent state when changing if ( registrationInfo?.address !== this.order.vehicle.registration?.address || registrationInfo?.city !== this.order.vehicle.registration?.city || registrationInfo?.state !== this.order.vehicle.registration?.state || registrationInfo?.zipCode !== this.order.vehicle.registration?.zipCode || registrationInfo?.firstName !== this.order.vehicle.registration?.firstName || registrationInfo?.lastName !== this.order.vehicle.registration?.lastName ) { if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); } // Save new values this.updateRegistration(registrationInfo); } if (vehicleInfo) { this.updateVehicle(vehicleInfo); } }, saveVin({ isSelectedGlassAvailableForVehicle, vehicleInfo }) { // Reset dependent state when changing if (vehicleInfo.vin !== this.order.vehicle.vin) { this.resetRegistrationAndDependencies(); if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); } // Save new values this.updateVehicle(vehicleInfo); } }, saveRegistrationLicensePlateLookup({ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }) { // Reset dependent state when changing if (registrationInfo?.licensePlate !== this.order.vehicle.registration?.licensePlate || registrationInfo?.state !== this.order.vehicle.registration?.state) { this.resetRegistrationAndDependencies(); if (!isSelectedGlassAvailableForVehicle) { // Dependencies already cleared in above statement this.resetDamageState(); this.resetGlassPartsState(); } // Save new values this.updateVehicle(vehicleInfo); } this.updateRegistration(registrationInfo); }, setBailout(bailoutData) { const params = new URL(document.location.toString()).searchParams; const currentPage = params.get('issPage'); this.updatePageData({ page: issPageValues.BAILOUT_PAGE, data: { url: window.location.href, page: currentPage || 'Unknown Page', bailoutCode: bailoutData.code, errorMessage: bailoutData.message, submit: false } }); }, setBailoutContactInfo(contact) { this.order.customer.firstName = contact.firstName; this.order.customer.lastName = contact.lastName; this.order.customer.emailAddress = contact.email; this.updatePhoneNumbers({ home: contact.phoneNumber, service: contact.phoneNumber }); this.pageData(issPageValues.BAILOUT_PAGE).submit = true; }, resetRegistrationAndDependencies() { this.resetRegistrationState(); this.resetGlassPartsState(); this.updateVaps(null); }, resetDamageAndDependencies() { this.resetDamageState(); this.resetGlassPartsState(); this.updateVaps(null); }, resetPartsAndDependencies() { this.resetGlassPartsState(); this.updateVaps(null); this.resetServiceLocationAndDependencies(); }, resetServiceLocation() { this.order.serviceLocation.state = null; this.order.serviceLocation.zipCode = null; this.order.serviceLocation.zipCodeCtu = null; this.order.serviceLocation.defaultProviderNumber = null; this.order.serviceLocation.appointmentType = null; this.order.serviceLocation.IsSafeliteProvider = null; this.resetServiceLocationProvider(); this.resetServiceLocationMobileAddress(); }, resetPageFields() { this.resetOrder(); this.resetCustomer(); this.resetPolicy(); this.resetPayment(); this.resetContactInfo(); this.resetVehicleState(); this.resetDamageState(); this.resetGlassPartsState(); this.resetInsurance(); this.resetServiceLocation(); this.resetSchedule(); this.resetBailout(); this.resetSubmittedOrder(); }, savePaymentMethodChoice(paymentMethod) { this.order.payment.paymentMethod = paymentMethod; }, getPaymentSignature() { return globalMethods.callHttpClient({ method: endpoints.GetPaymentSignature.method, endpoint: endpoints.GetPaymentSignature.url }); }, hasSubmittedOrder() { return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; }, getSubmittedOrder() { return JSON.parse(window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER)); }, async createSubmittedOrder(submitType) { if (this.hasSubmittedOrder()) { return; } await this.getCarrierAccountInfo(); const submittedOrder = this.order; const { experiments } = this.applicationUser; const { issConfig, hasRecalibrationPart } = this; submittedOrder.isUnverified = this.isUnverified; submittedOrder.isVerified = this.isVerified; submittedOrder.submitType = submitType; submittedOrder.payment.isPayInAdvance = this.isPayInAdvance; submittedOrder.hasRecalibrationPart = hasRecalibrationPart; // set to sessionStorage window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); // clear vuex this.resetState(); // delete cookie deleteISSCookie(); // restore issConfig this.issConfig = issConfig; // restore user's experiments this.applicationUser.experiments = experiments; }, resetSubmittedOrder() { // clear from sessionStorage window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); } }, persist: { // Default is localStorage, but sessionStorage is used here to ensure state is cleared when the browser tab is closed, preventing potential issues with stale data on return visits. storage: sessionStorage } }); // Private Functions function getHasRecalibrationPart(state) { const hasRequiresRecalibration = getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, 'requiresRecalibration')?.length > 0; const hasRecalibrationType = getNonFalseValuesOfPropertyInArrayOfObjects(state.order.lineItems.glassParts, 'recalibrationType')?.length > 0; if (hasRequiresRecalibration) { if (hasRecalibrationType) { // Has both 'requiresRecalibration' and 'recalibrationType' and 'recalibrationType' return ( getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.glassParts, 'recalibrationType' )[0].toLowerCase() !== 'unknown' ); } // Has 'requiresRecalibration' but no 'recalibrationType' at all return true; } // Does not have 'requiresRecalibration' return false; } function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) { return (array ?? []).map((x) => x[propertyName]).filter((x) => x); } function sortArrayOfObjectsByPropertyValue(arrayOfObjects, propertyName) { if (!arrayOfObjects) return null; return arrayOfObjects.sort((a, b) => { if (a[propertyName] < b[propertyName]) return -1; if (a[propertyName] > b[propertyName]) return 1; 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) { const partOffset = {}; lineItems.forEach((lineItem) => { if (lineItem.childParts) { addPricesToLineItems(lineItem.childParts, pricingLineItems); } const { partNumber } = lineItem; const pricedIndex = findLineItemIndex(pricingLineItems, partNumber, partOffset[partNumber] ?? 0); if (pricedIndex !== -1) { const pricedLineItem = pricingLineItems[pricedIndex]; lineItem.laborAmount = pricedLineItem.laborAmount; lineItem.sellingPrice = pricedLineItem.sellingPrice; lineItem.kitPrice = pricedLineItem.kitPrice; partOffset[partNumber] = pricedIndex + 1; } }); 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; } function convertGlassPieceToBackEndCompatibleFormat(glassPieces) { return glassPieces.map((glassPiece) => ({ location: glassPiece.glassLocation, name: glassPiece.glassName })); } 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 provisionalTriggersToString(provisionalTriggers) { return `ProvisionalTriggers:${provisionalTriggers.join(',')}`; } function setClearOnSubmit(lineItemArray, shouldClearOnSubmit) { const retArray = []; if (lineItemArray && lineItemArray.length > 0) { lineItemArray.forEach((part) => { const newPart = { ...part }; newPart.clearOnSubmit = shouldClearOnSubmit; retArray.push(newPart); }); } return retArray; }