/* eslint-disable no-use-before-define */ /* eslint-disable max-len */ import { defineStore } from 'pinia'; import { endpoints } from '@/constants/endpoints'; // eslint-disable-next-line import/no-cycle import { getDateForSavedSessionTimeout } from '@/helpers/session-helper'; // eslint-disable-next-line import/no-cycle import globalMethods from '@/global-methods'; import { experimentTriggers } from '@/constants/experiments'; import applicationConfig from '@/constants/application-config'; import issPageValues from '@/router/router-constants/issPage-values'; import damageLocationsSelected from '@/constants/damage-locations-selected'; import coverageStatuses from '@/constants/coverage-statuses'; import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants'; import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper'; import { paymentMethods } from '@/constants/payment-method-constants'; import { deductibleForSelectedVehicle, endorsementsForSelectedVehicle, noCoverageForSelectedVehicle, repairWaivedForSelectedVehicle } from '@/helpers/policy-vehicle-helper'; 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(',')}`; } 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 } }, 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, policyLookupSuccessful: null, noCoverage: 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, }, isITAC: false, 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, phoneNumber: null }, serviceLocation: { address: null, address2: null, city: null, state: null, zipCode: null, zipCodeCtu: null, appointmentType: null, isVehicleProtected: null, IsSafeliteProvider: null, searchFilter: 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, vaps: null }, payment: { insuranceCoverage: { isVerified: false, coverageStatus: coverageStatuses.PENDING, claimNumber: null }, parentAccountNumber: 0, isPayInAdvance: null, payInAdvanceType: null }, contactInfo: { firstName: null, lastName: null, emailAddress: null, phoneNumber: null, requestTextUpdates: false, notesForTechnician: '' }, schedule: { date: null, startTime: null, endTime: null, routeCode: null, jobMaxMinutes: null, jobMinMinutes: null }, referralNumber: null, referralDate: null, referralCorrelationId: '00000000-0000-0000-0000-000000000000', referralSequenceNumber: null, eon: null, workOrderNumber: null, originalDeductible: null, currentDeductible: null, loadedFromDupeCheck: null, loadedSessionClearedPreviousData: null }, 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 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. 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. 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 } } }); export const state = getDefaultState(); export const useMainStore = defineStore({ id: storeId, state: () => state, getters: { hasRecalibrationPart: (state) => getHasRecalibrationPart(state), vehicle: (state) => state.order.vehicle, damage: (state) => state.order.damage, lineItems: (state) => state.order.lineItems, payment: (state) => state.order.payment, policy: (state) => state.order.policy, hasExactlyOneChip: () => state.order.damage.numberOfChips === 1, isPolicyVehicle: () => state.order.vehicle.policyVehicleId != null, hasAnyNonWindshieldGlassParts: (s) => !s.order.policy.isDamageGlassOnly, 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, isClaimRegistrationRequired: (state) => state.issConfig.isClaimRegistrationRequired, isClaimAlreadyRegistered: (state) => state.order.payment.insuranceCoverage.claimNumber !== null, isBailout: (state) => state.applicationUser.pageData[issPageValues.BAILOUT_PAGE] != null, 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.contactInfo.firstName ?? s.order.customer.firstName, lastName: s.order.contactInfo.lastName ?? s.order.customer.lastName, emailAddress: s.order.contactInfo.emailAddress ?? s.order.customer.emailAddress, phoneNumber: s.order.contactInfo.phoneNumber ?? s.order.customer.phoneNumber, 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: (state) => ({ issVehicleYear: state.order.vehicle.year, issVehicleMake: state.order.vehicle.make, issVehicleModel: state.order.vehicle.model, issVehicleStyle: state.order.vehicle.style, issIsRepair: state.order.damage.isRepair, issNumberOfChips: state.order.damage.numberOfChips, issCarId: state.order.vehicle.carId, issServiceCity: state.order.serviceLocation.city, issServiceState: state.order.serviceLocation.state, issServiceZipCode: state.order.serviceLocation.zipCode, issParentAccountNumber: state.order.accountNumber, issIsCoverageVerified: state.order.payment.insuranceCoverage.isVerified, issHasRecalibrationPart: getHasRecalibrationPart(state), issSelectedMultiGlass: state.order.damage.glassToReplace?.length > 1, issSelectedWindshieldGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, 'glassLocation') .includes(damageLocationsSelected.WINDSHIELD), issSelectedBackGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, 'glassLocation') .includes(damageLocationsSelected.REAR), issSelectedDriverSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, 'glassLocation') .includes(damageLocationsSelected.DRIVER), issSelectedPassengerSideGlass: getNonFalseValuesOfPropertyInArrayOfObjects(state.order.damage.glassToReplace, 'glassLocation') .includes(damageLocationsSelected.PASSENGER), issOrderPartNumbers: [ ...getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.glassParts, 'partNumber' ), ...getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.otherParts, 'partNumber' ) ], issOrderPartTypes: [ ...getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.glassParts, 'recalibrationType' ), ...getNonFalseValuesOfPropertyInArrayOfObjects( state.order.lineItems.otherParts, 'recalibrationType' ) ] }), experimentSettings: (state) => state.applicationUser.experiments .map((x) => x.settings) .reduce((r, c) => Object.assign(r, c), {}) ?? {} }, 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() { return globalMethods.callHttpClient({ method: endpoints.GetVehicleModels.method, endpoint: `${endpoints.GetVehicleModels.url}/${this.order.vehicle.year}/${this.order.vehicle.make}`, payload: {} }); }, getVehicleStyles() { return globalMethods.callHttpClient({ method: endpoints.GetVehicleStyles.method, endpoint: `${endpoints.GetVehicleStyles.url}/${this.order.vehicle.year}/${this.order.vehicle.make}/${this.order.vehicle.model}`, 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 } }; } }, getCoveragePolicyInfo() { const { order } = this; const { policy } = order; this.applicationUser.coverageAttempts += 1; console.log(`Coverage lookup attempt #${this.applicationUser.coverageAttempts}. Max attempts allowed: 10.`); return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.CoveragePolicyInfo.method, endpoint: endpoints.CoveragePolicyInfo.url, payload: { accountNumber: order.accountNumber?.toString(), policyNumber: policy.policyNumber, dateOfLoss: policy.dateOfLoss, zipCode: policy.policyZipCode, referralCorrelationId: order.referralCorrelationId } }).then((r) => { const responsePolicy = r?.data?.policies?.[0]; policy.policyLookupSuccessful = !!responsePolicy; if (policy.policyLookupSuccessful) { const insured = responsePolicy.insureds?.[0]; // 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.serviceLocation.zipCode = insured?.zipCode?.toString(); order.policy.policyData = responsePolicy.policyData; // populate vehicles order.policy.vehicles = responsePolicy.vehicles ?? []; } return resolve(r); }).catch((error) => { policy.policyLookupSuccessful = false; return reject(error); }); }); }, registerClaim() { const nonNumberCharRegex = /[^0-9]/g; const { order } = this; return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.RegisterClaim.method, endpoint: endpoints.RegisterClaim.url, payload: { referralCorrelationId: this.order.referralCorrelationId, accountNumber: this.issConfig.parentAccountNumber?.toString() ?? '', policyData: this.order.policy.policyData, isItac: this.order.policy.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.order.customer.phoneNumber?.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.order.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) => { const registerClaimFailed = response.data.isError; order.payment.insuranceCoverage.isVerified = !registerClaimFailed; order.payment.insuranceCoverage.claimNumber = null; if (registerClaimFailed) { this.order.payment.insuranceCoverage.coverageStatus = coverageStatuses.PENDING; } else if (this.policy.noCoverage) { this.order.payment.insuranceCoverage.coverageStatus = coverageStatuses.NO_COMP; } else { this.order.payment.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED; this.order.payment.insuranceCoverage.claimNumber = response.data.claimNumber; } return resolve(response); }, (error) => { this.order.payment.insuranceCoverage.isVerified = false; this.order.payment.insuranceCoverage.coverageStatus = coverageStatuses.PENDING; this.order.payment.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.issConfig.parentAccountNumber?.toString() ?? '', endorsements: endorsementAnswersForPayload, manualGlassNames: manualGlassNamesArray, policyState: this.order.customer.address.state, status: this.order.policy.status, originalDeductible: this.order.originalDeductible, currentDeductible: this.order.currentDeductible, noCoverage: this.order.policy.noCoverage, 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.order.policy.isITAC } }).then((r) => { this.order.policy.policyData = r.data.policyData; this.updateDeductible(r.data.deductible); return resolve(r); }).catch((error) => reject(error)); }); }, getDuplicateReferrals() { return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.DuplicateSearch.method, endpoint: endpoints.DuplicateSearch.url( this.issConfig.parentAccountNumber, this.order.policy.policyNumber, this.order.policy.dateOfLoss ) }).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 } }); // 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 } }); // 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}` }); }, getPartFromCapabilityQuestionAnswer(glassLocation) { const pageData = this.pageData(issPageValues.CAPABILITY_QUESTIONS); const part = pageData.partsOrQuestions.find((x) => x.glassLocation === glassLocation) .parts[0]; const { capabilityQuestionAnswers } = this.order.damage; const capabilityQuestionAnswersForPart = capabilityQuestionAnswers.find((x) => x.glassLocation === glassLocation); return globalMethods.callHttpClient({ method: endpoints.GetPartFromCapabilityAnswer.method, endpoint: endpoints.GetPartFromCapabilityAnswer.url, payload: { part, capabilityAnswerResults: capabilityQuestionAnswersForPart } }); }, 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) { const { order } = this; const { vehicle } = this.order; let lineItems = [ ...(order.lineItems.supportingItems ?? []), ...(order.lineItems.vaps ?? []), ...getFlattenedArrayOfLineItemsWithChildParts(order.lineItems.glassParts) ]; 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.issConfig.parentAccountNumber.toString(), // TODO: MAKE THIS REAL parentAccountNumber: this.issConfig.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: order.serviceLocation.zipCode }; return globalMethods.callHttpClient({ method: endpoints.GetMobileTimeSlots.method, endpoint: endpoints.GetMobileTimeSlots.url, payload, logApiCall: true, additionalSuccessEventDataHandler: (response) => getTimeSlotsAdditionalEventData( response.data.provisionalTriggers, 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 ?? []), ...getFlattenedArrayOfLineItemsWithChildParts(order.lineItems.glassParts) ]; 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, applicationName: applicationConfig.APPLICATION_NAME, billToAccountNumber: order.policy.isITAC ? applicationConfig.ITAC_CASH_BILLTO : applicationConfig.ITAC_FAIR_AND_REASONABLE_BILLTO, // TODO: MAKE THIS REAL parentAccountNumber: this.issConfig.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; // WARNING // TODO: this is temp test code until serviceLocation is complete. // const serviceZipCode = this.order.serviceLocation.zipCode; const serviceZipCode = '44902'; 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 []; }); }, getProviders(serviceZipCode) { const damageType = this.damage.isRepair ? 'Repair' : 'Replace'; const shopRadiusInMiles = 100; return globalMethods.callHttpClient({ method: endpoints.GetProviders.method, endpoint: `${endpoints.GetProviders.url}/${serviceZipCode}/${damageType}/${shopRadiusInMiles}` }); }, getTpaProviders(zipCode, radius) { const damageType = this.damage.isRepair ? 'Repair' : 'Replace'; const { parentAccountNumber } = this.issConfig; const safeliteOnly = false; return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.GetProviders.method, endpoint: `${endpoints.GetProviders.url}/${zipCode}/${damageType}/${radius}/${parentAccountNumber}/${safeliteOnly}` }).then((response) => resolve(response), (error) => reject(error)); }); }, async getSupportingItems() { const glassPartsArray = this.order.lineItems.glassParts ?? []; const { carId } = this.order.vehicle; const { isRepair } = this.order.damage; const { numberOfChips } = this.order.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: glassPartsArray, numberOfRepairChips: isRepair ? numberOfChips : 0 } }); }, async getPriceOrderItems(availableLineItems) { const zipCodeToUse = this.order.serviceLocation.zipCode; if (!this.order.serviceLocation.zipCodeCtu) { const zipInfo = await this.validateZip({ zip: zipCodeToUse }); this.order.serviceLocation.zipCodeCtu = zipInfo.data.zipCodeCtu; } const ctuToUse = this.order.serviceLocation.zipCodeCtu; const availableLineItemsFormattedForRequest = getLineItemQueryStringForPricing(availableLineItems); const deductibleToUse = this.order.currentDeductible ?? 0; let queryString = `ParentAccountNumber=${this.order.accountNumber}` + `&CTU=${ctuToUse}` + `&Deductible=${deductibleToUse}` + `&ZipCode=${zipCodeToUse}` + `${availableLineItemsFormattedForRequest}`; const lineItemServerData = this.order.lineItems?.serverData; if (lineItemServerData) { queryString += `&ServerData=${encodeURIComponent(lineItemServerData)}`; } const response = await globalMethods .callHttpClient({ method: endpoints.GetInsurancePriceOrderItems.method, endpoint: `${endpoints.GetInsurancePriceOrderItems.url}?${queryString}` }).catch((error) => { console.error(error); throw error; }); if (response.data?.lineItems) { const retAvailableLineItems = addPricesToLineItems(availableLineItems, response.data.lineItems); return retAvailableLineItems; } return availableLineItems; }, getMobileFeePart() { const damageType = this.damage.isRepair ? 'Repair' : 'Replace'; const parentAccountNumber = 167132; // TODO: MAKE THIS REAL const billToAccountNumber = 87291; // TODO: MAKE THIS REAL return globalMethods.callHttpClient({ method: endpoints.GetMobileFeePart.method, endpoint: `${endpoints.GetMobileFeePart.url}/${damageType}/${parentAccountNumber}/${billToAccountNumber}` }); }, getServiceabilityDetails({ serviceZipCode }) { const lineItemsWithOnlyPartNumbers = this.order.lineItems.supportingItems.map((lineItem) => ({ partNumber: lineItem.partNumber })); const lineItems = buildQueryStringParameterFromArrayOfComplexObjects(lineItemsWithOnlyPartNumbers, 'lineItems'); const { vehicle } = this.order; const { carId } = vehicle; const { damage } = this.order; const glassArray = convertGlassPieceNamingForApi(damage.glassToReplace); const glassPieces = buildQueryStringParameterFromArrayOfComplexObjects(glassArray, 'glassPieces'); return globalMethods.callHttpClient({ method: endpoints.GetServiceabilityDetails.method, endpoint: `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&${lineItems}&${glassPieces}` }); }, lookupVehicleByVin(vin) { return globalMethods.callHttpClient({ method: endpoints.LookupVehicleByVin.method, endpoint: endpoints.LookupVehicleByVin.url, payload: { vin } }); }, setVehicle() { return globalMethods .callHttpClient({ method: endpoints.GetVehicle.method, endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${this.order.vehicle.make}/${this.order.vehicle.model}/${this.order.vehicle.style}`, payload: {} }) .then((response) => { 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.applicationUser.savedSessionId = response.savedSessionId; this.applicationUser.crmCustomerId = response.crmCustomerId.toString(); }, saveSession() { const { vehicle, damage, policy, customer, contactInfo, payment, lineItems, serviceLocation, schedule } = 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); } const loadedFromDupeCheck = !!(this.order.loadedFromDupeCheck && !this.order.loadedSessionClearedPreviousData); const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); return new Promise((resolve, reject) => { globalMethods.callHttpClient({ method: endpoints.SaveSession.method, endpoint: endpoints.SaveSession.url, 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: customer.phoneNumber, policyEmail: customer.emailAddress, policyState: customer.address.state }, policyNumber: policy.policyNumber, policyZipCode: policy.policyZipCode, noCoverage: policy.noCoverage, policyLookupSuccessful: policy.policyLookupSuccessful, originalDeductible: this.order.originalDeductible, currentDeductible: this.order.currentDeductible, IsItac: this.order.policy.isITAC, OemEndorsement: policy.endorsements?.indexOf('OEM Approved') !== -1 ?? false }, customer: { address: { streetAddress: customer.address?.streetAddress, streetAddress2: customer.address?.streetAddress2, city: customer.address?.city, state: customer.address?.state, zipCode: customer.address?.zipCode?.toString() }, emailAddress: contactInfo.emailAddress || customer.emailAddress, firstName: contactInfo.firstName || customer.firstName, lastName: contactInfo.lastName || customer.lastName, phoneNumber: contactInfo.phoneNumber, optInSms: contactInfo.requestTextUpdates ?? false }, lineItems: { glassParts: lineItems.glassParts, supportingItems: lineItems.supportingItems, vaps: lineItems.vaps }, payment: { InsuranceCoverage: { isVerified: payment.insuranceCoverage?.isVerified ?? false, coverageStatus: payment.insuranceCoverage?.coverageStatus, claimNumber: payment.insuranceCoverage?.claimNumber }, parentAccountNumber: this.issConfig.parentAccountNumber }, 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: serviceLocation.provider?.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, loadedFromDupeCheck }, additionalSuccessEventDataHandler: (response) => `Email provided: ${customer.emailAddress ? 'true' : 'false'}` }).then((response) => { if (loadedFromDupeCheck) { this.order.loadedSessionClearedPreviousData = true; } resolve(response); }, (error) => reject(error)); }); }, async loadSession() { const { applicationUser, order, issConfig } = this; // TODO how to get savedSessionId for a duplicate referral? try { const response = await globalMethods.callHttpClient({ method: endpoints.LoadSession.method, endpoint: endpoints.LoadSession.url, payload: { savedSessionId: applicationUser.savedSessionId?.toString(), referralNumber: order.referralNumber?.toString(), referralDate: order.referralDate?.toString(), parentAccountNumber: issConfig.parentAccountNumber, referralCorrelationId: order.referralCorrelationId } }); const { data } = response; if (!data) { // TODO how should we handle this case? return respone; } applicationUser.crmCustomerId = data.applicationUser?.crmCustomerId; applicationUser.experiments = data.applicationUser?.experiments ?? []; applicationUser.savedSessionId = data.applicationUser?.savedSessionId; if (order.policy.policyLookupSuccessful) { order.customer.emailAddress = data.customer?.emailAddress; order.customer.firstName = data.customer?.firstName; order.customer.lastName = data.customer?.lastName; order.customer.phoneNumber = data?.customer?.phoneNumber; 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.contactInfo.firstName = data?.customer?.firstName; order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; order.contactInfo.phoneNumber = data?.customer?.phoneNumber; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; order.payment.insuranceCoverage.isVerified = data?.payment?.insuranceCoverage?.isVerified; order.payment.insuranceCoverage.coverageStatus = data?.payment?.insuranceCoverage?.coverageStatus; order.payment.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) { Object.assign( vehicleResponse.data, { policyVehicleId: vehicle.id, vin: vehicle.vin, noCoverage: noCoverageForSelectedVehicle(vehicle), deductible: deductibleForSelectedVehicle(vehicle), repairWaived: repairWaivedForSelectedVehicle(vehicle), endorsements: endorsementsForSelectedVehicle(vehicle) } ); this.updateVehicle(vehicleResponse.data); } } } 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.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; return data; } catch (ex) { // TODO how should we handle this case? throw ex; } }, 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.address2 = serviceLocationInfo.address2; this.order.serviceLocation.city = serviceLocationInfo.city; this.order.serviceLocation.state = serviceLocationInfo.state; this.order.serviceLocation.zipCode = serviceLocationInfo.zipCode; this.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu; this.order.serviceLocation.appointmentType = serviceLocationInfo.appointmentType; this.order.serviceLocation.isVehicleProtected = serviceLocationInfo.isVehicleProtected; 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.searchFilter = serviceLocationInfo.searchFilter; }, 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(context) { this.resetServiceLocationAppointmentType(); this.resetServiceLocationProvider(); this.resetSchedule(); }, resetServiceLocationAppointmentType() { this.order.serviceLocation.appointmentType = null; }, resetServiceLocationProvider() { this.order.serviceLocation.provider = { providerNumber: 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.payment.insuranceCoverage.coverageStatus = coverageStatuses.PENDING; this.order.payment.insuranceCoverage.claimNumber = null; this.order.payment.insuranceCoverage.isVerified = false; }, updateSupportingItems(partsData) { this.order.lineItems.supportingItems = partsData; }, updateVaps(partsData) { this.order.lineItems.vaps = partsData; }, updateVehicle(vehicle) { // Assuming that the method caller pass all the properties. // otherwise need to check for undefined for every property. this.vehicle.policyVehicleId = vehicle.policyVehicleId; this.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.vin = vehicle.vin; this.order.vehicle.imageUrl = vehicle.imageUrl; this.order.vehicle.imageVifNumber = vehicle.imageVifNumber; this.order.vehicle.imageColor = vehicle.imageVifColor; // These could be undefined this.order.policy.noCoverage = vehicle.noCoverage; if (!this.order.payment.insuranceCoverage.claimNumber) { this.order.payment.insuranceCoverage.coverageStatus = vehicle.noCoverage ? coverageStatuses.NO_COMP : coverageStatuses.PENDING; } this.order.policy.deductible.replace = vehicle.deductible; this.order.policy.deductible.repair = vehicle?.repairWaived ?? false ? 0 : vehicle.deductible; this.order.policy.endorsements = vehicle?.endorsements; // TODO logic should be more complicated later on this.order.originalDeductible = vehicle.deductible; this.order.currentDeductible = vehicle.deductible; this.resetSupportingItemsState(); this.resetVapsState(); }, updateVehicleVin(vin) { this.order.vehicle.vin = vin; }, 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; }, resetGlassPartsState() { this.order.lineItems.glassParts = 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; // premium appointment fee used on schedule page also needs reset when schedule is reset const { supportingItems } = this.order.lineItems; const premiumAppointmentFeeIndex = supportingItems?.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE); if (premiumAppointmentFeeIndex >= 0) { supportingItems.splice(premiumAppointmentFeeIndex, 1); state.order.lineItems.supportingItems = supportingItems; } }, resetSupportingItemsState() { this.order.lineItems.supportingItems = null; }, resetVapsState() { this.order.lineItems.vaps = 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.clientDisplayName = 'Generic Insurance'; this.issConfig.clientHeader = {}; this.issConfig.parentAccountNumber = 0; this.issConfig.styleSheet = ''; this.issConfig.isCoverageEnabled = false; this.issConfig.isAuthenticated = 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; }, 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.customer.phoneNumber = welcomePageModel?.phoneNumber; this.order.customer.emailAddress = welcomePageModel?.email; }, 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.serviceLocation.zipCode = customerQuestions.addressQuestions.zipCode; }, updatePolicyITACFlag(isITAC) { this.order.policy.isITAC = isITAC; }, updateIsSafeliteProvider(isSafelite) { this.order.serviceLocation.IsSafeliteProvider = isSafelite; }, updateDeductible(finalDeductible) { this.order.currentDeductible = finalDeductible; }, 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.resetSupportingItemsState(); this.resetVapsState(); 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); }, saveGlassParts(glassParts) { this.order.lineItems.glassParts = glassParts; }, saveSupportingItems(supportingItems) { this.order.lineItems.supportingItems = supportingItems; }, saveSupportingItemsSuppressingStateResetting(supportingItems) { this.order.lineItems.supportingItems = supportingItems; }, saveVaps(vaps) { this.order.lineItems.vaps = vaps; }, // Price order actions async priceOrderItemsAndSaveServerData(availableLineItems, serviceZipCode, serviceZipCodeCtu) { const zipCodeToUse = serviceZipCode || this.order.serviceLocation.zipCode; const ctuToUse = serviceZipCodeCtu || this.order.serviceLocation.zipCodeCtu; const flattenedLineItemsWithChildParts = getFlattenedArrayOfLineItemsWithChildParts(availableLineItems); const lineItemsWithOnlyPartNumbers = flattenedLineItemsWithChildParts.map((lineItem) => ({ partNumber: lineItem.partNumber })); const availableLineItemsFormattedForRequest = buildQueryStringParameterFromArrayOfComplexObjects( lineItemsWithOnlyPartNumbers, 'lineItems' ); const { vehicle } = this.order; let queryString = `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` + `&CTU=${ctuToUse}` + `&CarId=${vehicle.carId}` + `&Make=${vehicle.make}` + `&Model=${vehicle.model}` + `&Year=${vehicle.year}` + `&EON=${this.order.eon}` + `&ZipCode=${zipCodeToUse}` + `&${availableLineItemsFormattedForRequest}`; const lineItemServerData = this.order.lineItems.serverData; if (lineItemServerData) { queryString += `&ServerData=${encodeURIComponent(lineItemServerData)}`; } const response = await globalMethods.callHttpClient({ method: endpoints.GetPriceOrderItems.method, endpoint: `${endpoints.GetPriceOrderItems.url}?${queryString}` }); // context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData); return addPricesToLineItems(availableLineItems, response.data.lineItems); }, saveProviderPreferenceData(data) { this.updatePageData({ page: issPageValues.PROVIDER_PREFERENCE, data }); }, 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() { if (!localStorage.getItem(storeId)) { 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({ userId, sessionKey, pageName, experiment }) { return globalMethods.callHttpClient({ method: endpoints.LogExperimentExposureIfAssigned.method, endpoint: endpoints.LogExperimentExposureIfAssigned.url, payload: { experimentForLogging: { userId, experimentUniverseId: experiment.universeId, experimentUniverseName: experiment.universeName, experimentTestId: experiment.testId, experimentTestName: experiment.testName, experimentVariationId: experiment.variationId, experimentVariationName: experiment.variationName, enabled: experiment.isActive, isExposed: experiment.isExposed, userPartitionNumber: experiment.userPartitionNumber, assignmentId: experiment.assignmentId, sessionKey, pageName } } }); }, 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}`); } ); }, 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.contactInfo.firstName = contactInfo?.firstName ?? ''; this.order.contactInfo.lastName = contactInfo?.lastName ?? ''; this.order.contactInfo.emailAddress = contactInfo?.emailAddress ?? ''; this.order.contactInfo.phoneNumber = contactInfo?.phoneNumber ?? ''; this.order.contactInfo.requestTextUpdates = contactInfo?.requestTextUpdates ?? false; this.order.contactInfo.notesForTechnician = contactInfo?.notesForTechnician ?? ''; }, GetExperimentsByUser(userId) { return globalMethods.callHttpClient({ method: endpoints.GetExperimentsByUser.method, endpoint: `${endpoints.GetExperimentsByUser.url}/${userId}`, payload: {} }); }, async runExperimentsForTrigger({ userId, triggerEvent, triggerValue }) { if (triggerEvent === experimentTriggers.SITE_ENTRY) { this.updateTriggeredSiteEntry(true); } const payload = { applicationName: applicationConfig.APPLICATION_NAME, userId, 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 }) { return await globalMethods.callHttpClient({ method: endpoints.ValidateZip.method, endpoint: `${endpoints.ValidateZip.url}/${zip}` }); }, 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) { if (this.order.serviceLocation) { if ( serviceLocationInfo.zipCode !== this.order.serviceLocation.zipCode || !providersEqual( serviceLocationInfo.provider, this.order.serviceLocation.provider ) || serviceLocationInfo.appointmentType !== this.order.serviceLocation.appointmentType ) { this.resetSchedule(); } } 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(currentRoute, bailoutData) { this.updatePageData({ page: issPageValues.BAILOUT_PAGE, data: { url: window.location.href, page: currentRoute.value?.name ?? currentRoute.name, 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.phoneNumber = contact.phoneNumber; this.order.customer.emailAddress = contact.email; this.pageData(issPageValues.BAILOUT_PAGE).submit = true; }, resetRegistrationAndDependencies() { this.resetRegistrationState(); this.resetGlassPartsState(); this.resetSupportingItemsState(); this.resetVapsState(); }, resetDamageAndDependencies() { this.resetDamageState(); this.resetGlassPartsState(); this.resetSupportingItemsState(); this.resetVapsState(); }, resetPartsAndDependencies() { this.resetGlassPartsState(); this.resetSupportingItemsState(); this.resetVapsState(); this.resetServiceLocationAndDependencies(); }, resetPageFields() { this.order.policy.policyNumber = null; this.order.policy.dateOfLoss = null; this.order.policy.damageCause = null; this.order.policy.damageCity = null; this.order.policy.damageState = null; this.order.policy.isITAC = false; this.order.customer.phoneNumber = null; 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; this.order.loadedFromDupeCheck = null; this.order.loadedSessionClearedPreviousData = null; this.resetVehicleState(); this.resetDamageState(); this.resetInsurance(); this.resetBailout(); }, savePaymentMethodChoice(paymentMethod) { const isPayInAdvance = paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE; this.order.payment.isPayInAdvance = isPayInAdvance; this.order.payment.payInAdvanceType = isPayInAdvance ? paymentMethod : null; }, getPaymentSignature() { return globalMethods.callHttpClient({ method: endpoints.GetPaymentSignature.method, endpoint: endpoints.GetPaymentSignature.url }); } }, persist: true }); // 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) { lineItems.forEach((lineItem) => { if (lineItem.childParts) { addPricesToLineItems(lineItem.childParts, pricingLineItems); } const lineItemIndex = pricingLineItems.findIndex((pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber); if (lineItemIndex > -1) { const pricedLineItem = pricingLineItems[lineItemIndex]; lineItem.laborAmount = pricedLineItem.laborAmount; lineItem.sellingPrice = pricedLineItem.sellingPrice; lineItem.kitPrice = pricedLineItem.kitPrice; } }); return lineItems; } function getLineItemQueryStringForPricing(lineItems) { return lineItems.map((lineItem, index) => { let queryStringSnippet = `&LineItems[${index}].partNumber=${lineItem.partNumber}`; if (lineItem.childParts) { queryStringSnippet += getLineItemQueryStringForPricing(lineItem.childParts); } return queryStringSnippet; }).join(''); } function getFlattenedArrayOfLineItemsWithChildParts(lineItems) { let flattenedArray = []; lineItems?.forEach((lineItem) => { flattenedArray.push(lineItem); if (lineItem.childParts) { flattenedArray = [ ...flattenedArray, ...getFlattenedArrayOfLineItemsWithChildParts(lineItem.childParts) ]; } }); return flattenedArray; } function buildQueryStringParameterFromArrayOfComplexObjects(arrayOfObjects, parameterName) { let queryStringParameter = ''; for (let i = 0; i < arrayOfObjects.length; i++) { for (const [key, value] of Object.entries(arrayOfObjects[i])) { queryStringParameter += `${parameterName}[${i}].${key}=${value}&`; } } // Remove trailing & return queryStringParameter.slice(0, -1); } 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(',')}`; }