From c7f54b8b7e0d5ab11b219bf0b30b00b3c7bce5ab Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 13 Jul 2023 12:04:01 -0400 Subject: [PATCH 001/674] Initial add of SaveSession --- src/constants/endpoints.js | 270 +++++++++++++++++++------------------ src/store/index.js | 139 +++++++++++++++++-- src/store/store.spec.js | 8 +- 3 files changed, 273 insertions(+), 144 deletions(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index be1ad311..782b7cf4 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -1,136 +1,142 @@ const endpoints = { - GetRouteInfo: { - url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/RouteInfo`, - method: 'POST' - }, - GetHomepageInfo: { - url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/HomepageInfo`, - method: 'GET' - }, - GetPageData: { - url: (applicationAbbreviation, pageName) => `/content/api/v1/content/${applicationAbbreviation}/${pageName}`, - method: 'GET' - }, - GetVehicleYears: { - url: '/vehicle/api/v1/vehicle/years', - method: 'GET' - }, - GetVehicleMakes: { - url: '/vehicle/api/v1/vehicle/makes/', - method: 'GET' - }, - GetVehicleModels: { - url: '/vehicle/api/v1/vehicle/models', - method: 'GET' - }, - GetVehicleStyles: { - url: '/vehicle/api/v1/vehicle/styles', - method: 'GET' - }, - GetDamageOptions: { - url: '/parts/api/v1/parts/damage-options', - method: 'GET' - }, - GetPartsOrQuestions: { - url: '/parts/api/v1/parts/parts-or-questions', - method: 'POST' - }, - GetParts: { - url: '/parts/api/v1/parts/parts', - method: 'POST' - }, - GetPriceOrderItems: { - url: '/price/api/v1/price/order-items', - method: 'GET' - }, - GetCapabilityQuestions: { - url: '/parts/api/v1/parts/capability-questions', - method: 'GET' - }, - GetPartFromCapabilityAnswer: { - url: '/parts/api/v1/parts/part-from-capability-answer', - method: 'POST' - }, - GetWipers: { - url: '/parts/api/v1/parts/wipers', - method: 'GET' - }, - GetRainDefense: { - url: '/parts/api/v1/parts/rain-defense', - method: 'GET' - }, - GetSupportingItems: { - url: '/parts/api/v1/parts/supporting-items', - method: 'POST' + GetRouteInfo: { + url: (applicationAbbreviation) => + `/content/api/v1/content/${applicationAbbreviation}/RouteInfo`, + method: 'POST' }, - GetServiceabilityDetails: { - url: "/location/api/v1/location/serviceability-details", - method: "GET", - }, - GetVehicle: { - url: '/vehicle/api/v1/vehicle/lookup', - method: 'GET' - }, - LogExperimentExposureIfAssigned: { - url: '/experiments/api/v1/experiments/log-exposure', - method: 'POST' - }, - LogPageView: { - url: '/analytics/api/v1/analytics/log-page-view', - method: 'POST' - }, - LogCustomEvent: { - url: '/analytics/api/v1/analytics/log-custom-event', - method: 'POST' - }, - LookupVehicleByVin: { - url: '/vehicle/api/v1/vehicle/lookup', - method: 'POST' - }, - LookupVinByAddress: { - url: '/vehicle/api/v1/vehicle/lookup-vin-by-address', - method: 'POST' - }, - LookupVinByPlate: { - url: '/vehicle/api/v1/vehicle/lookup-vin-by-plate', - method: 'POST' - }, - InitializeSession: { - url: '/analytics/api/v1/analytics/initialize', - method: 'POST' - }, - GetExperimentsByUser: { - url: '/analytics/api/v1/analytics/get-experiments', - method: 'GET' - }, - RunExperimentsForTrigger: { - url: '/experiments/api/v1/experiments/run', - method: 'POST' - }, - ValidateZip: { - url: '/location/api/v1/location/zip', - method: 'GET' - }, - GooglePlaces: { - url: 'https://maps.googleapis.com/maps/api/js?key={apiKey}&libraries=places' - }, - ValidateClientTag: { - url: '/clientauth/api/v1/clientauth/validate-client-tag', - method: 'GET' - }, - IsVinbyAddressPermissible:{ - url:'/vehicle/api/v1/vehicle/is-vin-by-address-permissible', - method:'Get' - }, - CoveragePolicyInfo: { - url: '/coverage/api/v1/coverage/get-policy-information', - method: 'POST' - }, - RegisterClaim: { - url: '/coverage/api/v1/coverage/register-claim', - method: 'POST' - } + GetHomepageInfo: { + url: (applicationAbbreviation) => + `/content/api/v1/content/${applicationAbbreviation}/HomepageInfo`, + method: 'GET' + }, + GetPageData: { + url: (applicationAbbreviation, pageName) => + `/content/api/v1/content/${applicationAbbreviation}/${pageName}`, + method: 'GET' + }, + GetVehicleYears: { + url: '/vehicle/api/v1/vehicle/years', + method: 'GET' + }, + GetVehicleMakes: { + url: '/vehicle/api/v1/vehicle/makes/', + method: 'GET' + }, + GetVehicleModels: { + url: '/vehicle/api/v1/vehicle/models', + method: 'GET' + }, + GetVehicleStyles: { + url: '/vehicle/api/v1/vehicle/styles', + method: 'GET' + }, + GetDamageOptions: { + url: '/parts/api/v1/parts/damage-options', + method: 'GET' + }, + GetPartsOrQuestions: { + url: '/parts/api/v1/parts/parts-or-questions', + method: 'POST' + }, + GetParts: { + url: '/parts/api/v1/parts/parts', + method: 'POST' + }, + GetPriceOrderItems: { + url: '/price/api/v1/price/order-items', + method: 'GET' + }, + GetCapabilityQuestions: { + url: '/parts/api/v1/parts/capability-questions', + method: 'GET' + }, + GetPartFromCapabilityAnswer: { + url: '/parts/api/v1/parts/part-from-capability-answer', + method: 'POST' + }, + GetWipers: { + url: '/parts/api/v1/parts/wipers', + method: 'GET' + }, + GetRainDefense: { + url: '/parts/api/v1/parts/rain-defense', + method: 'GET' + }, + GetSupportingItems: { + url: '/parts/api/v1/parts/supporting-items', + method: 'POST' + }, + GetServiceabilityDetails: { + url: '/location/api/v1/location/serviceability-details', + method: 'GET' + }, + GetVehicle: { + url: '/vehicle/api/v1/vehicle/lookup', + method: 'GET' + }, + LogExperimentExposureIfAssigned: { + url: '/experiments/api/v1/experiments/log-exposure', + method: 'POST' + }, + LogPageView: { + url: '/analytics/api/v1/analytics/log-page-view', + method: 'POST' + }, + LogCustomEvent: { + url: '/analytics/api/v1/analytics/log-custom-event', + method: 'POST' + }, + LookupVehicleByVin: { + url: '/vehicle/api/v1/vehicle/lookup', + method: 'POST' + }, + LookupVinByAddress: { + url: '/vehicle/api/v1/vehicle/lookup-vin-by-address', + method: 'POST' + }, + LookupVinByPlate: { + url: '/vehicle/api/v1/vehicle/lookup-vin-by-plate', + method: 'POST' + }, + InitializeSession: { + url: '/analytics/api/v1/analytics/initialize', + method: 'POST' + }, + GetExperimentsByUser: { + url: '/analytics/api/v1/analytics/get-experiments', + method: 'GET' + }, + RunExperimentsForTrigger: { + url: '/experiments/api/v1/experiments/run', + method: 'POST' + }, + ValidateZip: { + url: '/location/api/v1/location/zip', + method: 'GET' + }, + GooglePlaces: { + url: 'https://maps.googleapis.com/maps/api/js?key={apiKey}&libraries=places' + }, + ValidateClientTag: { + url: '/clientauth/api/v1/clientauth/validate-client-tag', + method: 'GET' + }, + IsVinbyAddressPermissible:{ + url: '/vehicle/api/v1/vehicle/is-vin-by-address-permissible', + method: 'Get' + }, + CoveragePolicyInfo: { + url: '/coverage/api/v1/coverage/get-policy-information', + method: 'POST' + }, + RegisterClaim: { + url: '/coverage/api/v1/coverage/register-claim', + method: 'POST' + }, + SaveSession: { + url: '/order/api/v1/order/save-session', + method: 'POST' + } }; - + export { endpoints }; - \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index f04f4c68..d1b7f508 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,3 +1,5 @@ +/* eslint-disable no-shadow */ +/* eslint-disable no-use-before-define */ /* eslint-disable max-len */ import { defineStore } from 'pinia'; import { endpoints } from '@/constants/endpoints'; @@ -16,6 +18,7 @@ const storeId = 'main'; const getDefaultState = () => ({ order: { + // Same as FMG vehicle: { year: null, make: null, @@ -37,6 +40,7 @@ const getDefaultState = () => lastName: null } }, + // Same as FMG damage: { isRepair: null, numberOfChips: null, @@ -45,6 +49,7 @@ const getDefaultState = () => moldingQuestionAnswers: null, capabilityQuestionAnswers: null }, + // DNE in FMG policy: { policyNumber: null, policyZipCode: null, @@ -59,6 +64,7 @@ const getDefaultState = () => replace: null // numerical value; how much customer owes on deductible in replace case, } }, + // FMG only has email customer: { address: { streetAddress: null, @@ -72,6 +78,7 @@ const getDefaultState = () => emailAddress: null, phoneNumber: null }, + // Many more details in FMG serviceLocation: { address: null, city: null, @@ -79,21 +86,24 @@ const getDefaultState = () => zipCode: null, zipCodeCtu: null }, + // otherParts vs serverData lineItems: { glassParts: null, - otherParts: null, + otherParts: null, // TODO what is this? supportingItems: null, - vaps: null + vaps: null, + serverData: null // TODO what is this for and should it be added? }, + // Add parent account number from FMG payment: { isInsurance: true, insuranceCoverage: { isVerified: false, coverageStatus: coverageStatuses.PENDING - } + }, + parentAccountNumber: 0 // TODO what is this for and where set? }, - referralNumber: null, - referralDate: null, + // DNE in FMG contactInfo: { firstName: null, lastName: null, @@ -101,7 +111,18 @@ const getDefaultState = () => phoneNumber: null, requestTextUpdates: false, notesForTechnician: '' - } + }, + schedule: { + date: null, + startTime: null, + endTime: null, + routeCode: null, + jobMaxMinutes: null + }, + referralNumber: null, + referralDate: null, + referralCorrelationId: null, // TODO when is this set + eon: null // TODO what is this }, applicationUser: { experiments: [], @@ -679,6 +700,108 @@ export const useMainStore = defineStore({ }); }, + saveSession() { + // TODO use pieces of actual store + const { vehicle, damage, order, applicationUser, lineItems } = this.order; + + // TODO what does this method do + const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); + + return globalMethods.callHttpClient({ + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url, + // TODO update with payload for our store + payload: { + applicationUser: { + crmCustomerId: applicationUser.crmCustomerId, + experiments: applicationUser.experiments, + lastPage: applicationUser.lastPageVisited, + pageData: applicationUser.pageData, + savedSessionId: applicationUser.savedSessionId, + }, + order: { + vehicle: { + carId: vehicle.carId, + year: vehicle.year, + make: vehicle.make, + model: vehicle.model, + style: vehicle.style, + vin: vehicle.vin, + registration: { + firstName: vehicle.registration.firstName, + lastName: vehicle.registration.lastName, + streetAddress: vehicle.registration.address, + city: vehicle.registration.city, + state: vehicle.registration.state, + zipCode: vehicle.registration.zipCode, + licensePlateNumber: vehicle.registration.licensePlate, + }, + }, + customer: { + emailAddress: order.customer.emailAddress, + }, + damage: { + numberOfChips: damage.numberOfChips, + glassToReplace: newGlassToReplace, + isRepair: damage.isRepair, + partQuestionAnswers: order.damage.partQuestionAnswers, + moldingQuestionAnswers: order.damage.moldingQuestionAnswers, + capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers, + }, + lineItems: { + glassParts: lineItems.glassParts, + supportingItems: lineItems.supportingItems, + vaps: lineItems.vaps, + serverData: lineItems.serverData, + }, + payment: { + InsuranceCoverage: { + isVerified: order.payment.insuranceCoverage.isVerified ?? false, + }, + isInsurance: order.payment.isInsurance ?? false, + parentAccountNumber: order.payment.parentAccountNumber, + }, + serviceLocation: { + streetAddress: order.serviceLocation.address, + streetAddress2: order.serviceLocation.address2, + city: order.serviceLocation.city, + state: order.serviceLocation.state, + zipCode: order.serviceLocation.zipCode, + zipCodeCtu: order.serviceLocation.zipCodeCtu, + appointmentType: order.serviceLocation.appointmentType, + isVehicleProtected: order.serviceLocation.isVehicleProtected, + provider: { + providerNumber: order.serviceLocation.provider?.providerNumber, + address: { + streetAddress: + order.serviceLocation.provider?.address?.streetAddress, + city: order.serviceLocation.provider?.address?.city, + state: order.serviceLocation.provider?.address?.state, + zipCode: order.serviceLocation.provider?.address?.zipCode, + zipCodeCtu: order.serviceLocation.provider?.address?.zipCodeCtu, + }, + }, + }, + schedule: { + date: order.schedule?.date, + startTime: order.schedule?.startTime, + endTime: order.schedule?.endTime, + routeCode: order.schedule?.routeCode, + jobMaxMinutes: order.schedule?.jobMaxMinutes, + }, + existingPromoCode: null, + referralCorrelationId: order.referralCorrelationId, + referralDate: order.referralDate, + referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place + referralSequenceNumber: order.referralNumber?.toString(), // TODO Pass the referralSequence number once insurance flow creates it + eon: order.eon + } + }, + additionalSuccessEventDataHandler: (response) => + `Email provided: ${order.customer.emailAddress ? 'true' : 'false'}` + }); + }, + saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) { const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort(); const isGlassToReplaceTheSame @@ -1177,14 +1300,14 @@ export const useMainStore = defineStore({ }, async validateZip({ zip }) { - return await globalMethods.callHttpClient({ + return globalMethods.callHttpClient({ methods: endpoints.ValidateZip.method, endpoint: `${endpoints.ValidateZip.url}/${zip}` }); }, async validateClientTag(clientTag) { - return await globalMethods.callHttpClient({ + return globalMethods.callHttpClient({ methods: endpoints.ValidateClientTag.method, endpoint: `${endpoints.ValidateClientTag.url}/${clientTag}` }); diff --git a/src/store/store.spec.js b/src/store/store.spec.js index da26b1ac..8a629fdc 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -7,11 +7,10 @@ import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from ' import { coverageStatuses } from "@/constants/coverage-statuses.js"; describe("Store", () => { - let store; const vueApp = createApp(App); - + beforeEach(() => { const pinia = createPinia(); setActivePinia(pinia); @@ -20,8 +19,7 @@ describe("Store", () => { store.applicationUser.eventBus = []; jest.resetAllMocks(); }); - - + it("Should Store Vehicle Year", () => { let testYear = "2001"; store.updateVehicleYear(testYear); @@ -463,4 +461,6 @@ describe("Store", () => { expect(store.contactInfo.notesForTechnician).toEqual(''); }); }); + // TODO add tests + describe('saveSession method', () => {}); }); From 242b947b14bae0194b6f43d2b3c74bc760fd51d4 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Fri, 14 Jul 2023 08:38:08 -0400 Subject: [PATCH 002/674] Adding consumer model to save session --- src/store/index.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index d1b7f508..96cda682 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -720,6 +720,7 @@ export const useMainStore = defineStore({ savedSessionId: applicationUser.savedSessionId, }, order: { + // done vehicle: { carId: vehicle.carId, year: vehicle.year, @@ -737,9 +738,7 @@ export const useMainStore = defineStore({ licensePlateNumber: vehicle.registration.licensePlate, }, }, - customer: { - emailAddress: order.customer.emailAddress, - }, + // done damage: { numberOfChips: damage.numberOfChips, glassToReplace: newGlassToReplace, @@ -748,6 +747,13 @@ export const useMainStore = defineStore({ moldingQuestionAnswers: order.damage.moldingQuestionAnswers, capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers, }, + customer: { + emailAddress: order.customer.emailAddress, + firstName: order.customer.firstName, + lastName: order.customer.lastName, + phoneNumber: order.customer.phone, // TODO contact info or customer? + optInSms: order.contactInfo.requestTextUpdates + }, lineItems: { glassParts: lineItems.glassParts, supportingItems: lineItems.supportingItems, From 244b098dcf6c49ec56e67cd3ddf92f23b6c4c7db Mon Sep 17 00:00:00 2001 From: brydon1 Date: Fri, 14 Jul 2023 10:46:59 -0400 Subject: [PATCH 003/674] Removing trailing commas --- src/store/index.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 96cda682..648832b9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -65,6 +65,7 @@ const getDefaultState = () => } }, // FMG only has email + // CSR-1358 and CSR-1359 customer: { address: { streetAddress: null, @@ -92,11 +93,11 @@ const getDefaultState = () => otherParts: null, // TODO what is this? supportingItems: null, vaps: null, - serverData: null // TODO what is this for and should it be added? + serverData: null // TODO add }, // Add parent account number from FMG payment: { - isInsurance: true, + isInsurance: true, // TODO delete; irrelevant to ISS insuranceCoverage: { isVerified: false, coverageStatus: coverageStatuses.PENDING @@ -121,8 +122,7 @@ const getDefaultState = () => }, referralNumber: null, referralDate: null, - referralCorrelationId: null, // TODO when is this set - eon: null // TODO what is this + eon: null // TODO add }, applicationUser: { experiments: [], @@ -717,7 +717,7 @@ export const useMainStore = defineStore({ experiments: applicationUser.experiments, lastPage: applicationUser.lastPageVisited, pageData: applicationUser.pageData, - savedSessionId: applicationUser.savedSessionId, + savedSessionId: applicationUser.savedSessionId }, order: { // done @@ -735,8 +735,8 @@ export const useMainStore = defineStore({ city: vehicle.registration.city, state: vehicle.registration.state, zipCode: vehicle.registration.zipCode, - licensePlateNumber: vehicle.registration.licensePlate, - }, + licensePlateNumber: vehicle.registration.licensePlate + } }, // done damage: { @@ -745,14 +745,14 @@ export const useMainStore = defineStore({ isRepair: damage.isRepair, partQuestionAnswers: order.damage.partQuestionAnswers, moldingQuestionAnswers: order.damage.moldingQuestionAnswers, - capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers, + capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers }, customer: { - emailAddress: order.customer.emailAddress, - firstName: order.customer.firstName, - lastName: order.customer.lastName, - phoneNumber: order.customer.phone, // TODO contact info or customer? - optInSms: order.contactInfo.requestTextUpdates + emailAddress: order.contactInfo.emailAddress ?? order.customer.emailAddress, + firstName: order.contactInfo.firstName ?? order.customer.firstName, + lastName: order.contactInfo.lastName ?? order.customer.lastName, + phoneNumber: order.contactInfo.phoneNumber ?? order.customer.phoneNumber, // TODO contact info or customer? + optInSms: order.contactInfo.requestTextUpdates ?? false }, lineItems: { glassParts: lineItems.glassParts, From cbb80a0cd54bf990370b754ce971a1f9b07ee555 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 20 Jul 2023 14:37:19 -0400 Subject: [PATCH 004/674] Partial work --- src/store/index.js | 81 +++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 0e662b91..a490ac86 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,16 +2,16 @@ /* eslint-disable no-use-before-define */ /* eslint-disable max-len */ import { defineStore } from 'pinia'; -import { endpoints } from '@/constants/endpoints'; +import { endpoints } from '@/constants/endpoints.js'; // eslint-disable-next-line import/no-cycle -import { getDateForSavedSessionTimeout } from '@/helpers/session-helper'; +import { getDateForSavedSessionTimeout } from '@/helpers/session-helper.js'; // 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 globalMethods from '@/global-methods.js'; +import { experimentTriggers } from '@/constants/experiments.js'; +import { applicationConfig } from '@/constants/application-config.js'; +import { issPageValues } from '@/router/router-constants/issPage-values.js'; +import { damageLocationsSelected } from '@/constants/damage-locations-selected.js'; +import { coverageStatuses } from '@/constants/coverage-statuses.js'; const storeId = 'main'; @@ -121,8 +121,7 @@ const getDefaultState = () => jobMaxMinutes: null }, referralNumber: null, - referralDate: null, - eon: null // TODO add + referralDate: null }, applicationUser: { experiments: [], @@ -709,7 +708,7 @@ export const useMainStore = defineStore({ saveSession() { // TODO use pieces of actual store - const { vehicle, damage, order, applicationUser, lineItems } = this.order; + const { vehicle, damage, policy, order, applicationUser, lineItems } = this.order; // TODO what does this method do const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); @@ -717,8 +716,8 @@ export const useMainStore = defineStore({ return globalMethods.callHttpClient({ method: endpoints.SaveSession.method, endpoint: endpoints.SaveSession.url, - // TODO update with payload for our store payload: { + // done applicationUser: { crmCustomerId: applicationUser.crmCustomerId, experiments: applicationUser.experiments, @@ -754,46 +753,48 @@ export const useMainStore = defineStore({ moldingQuestionAnswers: order.damage.moldingQuestionAnswers, capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers }, + policy: { + policyNumber: policy.policyNumber, + policyZipCode: policy.policyZipCode, + dateOfLoss: policy.dateOfLoss, + damageCause: policy.damageCause, + damageState: policy.damageState, + damageCity: policy.damageCity, + isDamageGlassOnly: policy.isDamageGlassOnly, + noCoverage: policy.noCoverage + // deductible: { + // repair: policy.deductible.repair, + // replace: policy.deductible.replace + // } + }, + // NOTE using only customer info for now; ignoring contact details customer: { - emailAddress: order.contactInfo.emailAddress ?? order.customer.emailAddress, - firstName: order.contactInfo.firstName ?? order.customer.firstName, - lastName: order.contactInfo.lastName ?? order.customer.lastName, - phoneNumber: order.contactInfo.phoneNumber ?? order.customer.phoneNumber, // TODO contact info or customer? + emailAddress: order.customer.emailAddress, + firstName: order.customer.firstName, + lastName: order.customer.lastName, + phoneNumber: order.customer.phoneNumber, optInSms: order.contactInfo.requestTextUpdates ?? false }, lineItems: { glassParts: lineItems.glassParts, + otherData: lineItems.otherData, supportingItems: lineItems.supportingItems, - vaps: lineItems.vaps, - serverData: lineItems.serverData, + vaps: lineItems.vaps }, payment: { InsuranceCoverage: { isVerified: order.payment.insuranceCoverage.isVerified ?? false, + coverageStatus: order.payment.insuranceCoverage.coverageStatus }, - isInsurance: order.payment.isInsurance ?? false, - parentAccountNumber: order.payment.parentAccountNumber, + isInsurance: order.payment.isInsurance ?? true, + parentAccountNumber: order.payment.parentAccountNumber }, serviceLocation: { streetAddress: order.serviceLocation.address, - streetAddress2: order.serviceLocation.address2, city: order.serviceLocation.city, state: order.serviceLocation.state, zipCode: order.serviceLocation.zipCode, - zipCodeCtu: order.serviceLocation.zipCodeCtu, - appointmentType: order.serviceLocation.appointmentType, - isVehicleProtected: order.serviceLocation.isVehicleProtected, - provider: { - providerNumber: order.serviceLocation.provider?.providerNumber, - address: { - streetAddress: - order.serviceLocation.provider?.address?.streetAddress, - city: order.serviceLocation.provider?.address?.city, - state: order.serviceLocation.provider?.address?.state, - zipCode: order.serviceLocation.provider?.address?.zipCode, - zipCodeCtu: order.serviceLocation.provider?.address?.zipCodeCtu, - }, - }, + zipCodeCtu: order.serviceLocation.zipCodeCtu }, schedule: { date: order.schedule?.date, @@ -802,14 +803,14 @@ export const useMainStore = defineStore({ routeCode: order.schedule?.routeCode, jobMaxMinutes: order.schedule?.jobMaxMinutes, }, - existingPromoCode: null, - referralCorrelationId: order.referralCorrelationId, referralDate: order.referralDate, - referralNumber: order.referralNumber?.toString(), // TODO It'd be nice to save these as strings in the first place - referralSequenceNumber: order.referralNumber?.toString(), // TODO Pass the referralSequence number once insurance flow creates it - eon: order.eon + referralNumber: order.referralNumber?.toString(), + // TODO set + originalDeductible: 0, + currentDeductible: 0 } }, + // TODO maybe modify additionalSuccessEventDataHandler: (response) => `Email provided: ${order.customer.emailAddress ? 'true' : 'false'}` }); From 0ba2a79d5feb2a8ab64184a99e116791be1adc4c Mon Sep 17 00:00:00 2001 From: brydon1 Date: Mon, 24 Jul 2023 14:22:37 -0400 Subject: [PATCH 005/674] Finalizing --- src/store/index.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index a490ac86..67fad3d6 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -762,17 +762,14 @@ export const useMainStore = defineStore({ damageCity: policy.damageCity, isDamageGlassOnly: policy.isDamageGlassOnly, noCoverage: policy.noCoverage - // deductible: { - // repair: policy.deductible.repair, - // replace: policy.deductible.replace - // } }, - // NOTE using only customer info for now; ignoring contact details + // TODO incorporate name and email contact details where appropriate customer: { emailAddress: order.customer.emailAddress, firstName: order.customer.firstName, lastName: order.customer.lastName, - phoneNumber: order.customer.phoneNumber, + policyPhoneNumber: order.customer.phoneNumber, + smsPhoneNumber: order.contactInfo.requestTextUpdates ? order.contactInfo.phoneNumber : null, optInSms: order.contactInfo.requestTextUpdates ?? false }, lineItems: { @@ -787,7 +784,7 @@ export const useMainStore = defineStore({ coverageStatus: order.payment.insuranceCoverage.coverageStatus }, isInsurance: order.payment.isInsurance ?? true, - parentAccountNumber: order.payment.parentAccountNumber + parentAccountNumber: this.issConfig.accountNumber }, serviceLocation: { streetAddress: order.serviceLocation.address, @@ -801,13 +798,12 @@ export const useMainStore = defineStore({ startTime: order.schedule?.startTime, endTime: order.schedule?.endTime, routeCode: order.schedule?.routeCode, - jobMaxMinutes: order.schedule?.jobMaxMinutes, + jobMaxMinutes: order.schedule?.jobMaxMinutes }, referralDate: order.referralDate, referralNumber: order.referralNumber?.toString(), - // TODO set - originalDeductible: 0, - currentDeductible: 0 + originalDeductible: order.originalDeductible, + currentDeductible: order.currentDeductible } }, // TODO maybe modify From 20ca807c37ae830802f4d81d104d1e77527bba6c Mon Sep 17 00:00:00 2001 From: brydon1 Date: Fri, 28 Jul 2023 16:00:37 -0400 Subject: [PATCH 006/674] Adding content to save session request --- src/store/index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/store/index.js b/src/store/index.js index 67fad3d6..2ff0dc8a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -734,6 +734,9 @@ export const useMainStore = defineStore({ model: vehicle.model, style: vehicle.style, vin: vehicle.vin, + imageUrl: vehicle.imageUrl, + imageVifColor: vehicle.imageColor, + imageVifNumber: vehicle.imageVifNumber, registration: { firstName: vehicle.registration.firstName, lastName: vehicle.registration.lastName, @@ -765,6 +768,13 @@ export const useMainStore = defineStore({ }, // TODO incorporate name and email contact details where appropriate customer: { + address: { + streetAddress: order.customer.address.streetAddress, + streetAddress2: order.customer.address.streetAddress2, + city: order.customer.address.city, + state: order.customer.address.state, + zipCode: order.customer.address.zipCode + }, emailAddress: order.customer.emailAddress, firstName: order.customer.firstName, lastName: order.customer.lastName, From 431a0fad5410e0f5f0187c362749b28c019b1ba1 Mon Sep 17 00:00:00 2001 From: DavidAtSafelite Date: Tue, 8 Aug 2023 07:27:33 -0400 Subject: [PATCH 007/674] A couple of hopefully minor package updates. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a249d5e6..b2cd80d7 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,14 @@ }, "dependencies": { "axios": "^0.27.2", - "bootstrap": "^5.2.3", + "bootstrap": "^5.3", "maska": "^1.5.0", "pinia": "^2.0.22", "pinia-plugin-persistedstate": "^2.2.0", "vee-validate": "^4.7.0", "vue": "^3.3.4", "vue-plugin-load-script": "^2.1.0", - "vue-router": "4.1.3" + "vue-router": "4.2.4" }, "devDependencies": { "@pinia/testing": "0.1.2", From a6e1a38d5addb7d418d6d461970240f13d0489eb Mon Sep 17 00:00:00 2001 From: Jeremy Zimmerman Date: Tue, 8 Aug 2023 12:35:30 -0400 Subject: [PATCH 008/674] Updating the lock file. --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0543b3b7..0e085493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,14 @@ "version": "0.1.0", "dependencies": { "axios": "^0.27.2", - "bootstrap": "^5.2.3", + "bootstrap": "^5.3", "maska": "^1.5.0", "pinia": "^2.0.22", "pinia-plugin-persistedstate": "^2.2.0", "vee-validate": "^4.7.0", - "vue": "^3.2.13", + "vue": "^3.3.4", "vue-plugin-load-script": "^2.1.0", - "vue-router": "4.1.3" + "vue-router": "4.2.4" }, "devDependencies": { "@pinia/testing": "0.1.2", @@ -17494,11 +17494,11 @@ "integrity": "sha512-tFvedqtOiLI+jZ78dymg+f7bjiglCVC2lA0CXVIq7bXVqu1sssP40r6UNMpD9glGD+EhbGRdOa70Sb5ZuHjmTA==" }, "node_modules/vue-router": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.3.tgz", - "integrity": "sha512-XvK81bcYglKiayT7/vYAg/f36ExPC4t90R/HIpzrZ5x+17BOWptXLCrEPufGgZeuq68ww4ekSIMBZY1qdUdfjA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz", + "integrity": "sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==", "dependencies": { - "@vue/devtools-api": "^6.1.4" + "@vue/devtools-api": "^6.5.0" }, "funding": { "url": "https://github.com/sponsors/posva" From 2f09667b483fd784259aca6b81ae85b42fc64263 Mon Sep 17 00:00:00 2001 From: DavidAtSafelite Date: Tue, 8 Aug 2023 13:08:28 -0400 Subject: [PATCH 009/674] Updated pinia package --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e085493..38bbeaa3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "axios": "^0.27.2", "bootstrap": "^5.3", "maska": "^1.5.0", - "pinia": "^2.0.22", + "pinia": "^2.1.4", "pinia-plugin-persistedstate": "^2.2.0", "vee-validate": "^4.7.0", "vue": "^3.3.4", diff --git a/package.json b/package.json index b2cd80d7..c100b7d1 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "axios": "^0.27.2", "bootstrap": "^5.3", "maska": "^1.5.0", - "pinia": "^2.0.22", + "pinia": "^2.1.4", "pinia-plugin-persistedstate": "^2.2.0", "vee-validate": "^4.7.0", "vue": "^3.3.4", From 7f91d76df467c8894975f39d6dd66ae8492b62af Mon Sep 17 00:00:00 2001 From: DavidAtSafelite Date: Tue, 8 Aug 2023 14:15:04 -0400 Subject: [PATCH 010/674] Updated axios --- jest.config.js | 3 +++ package-lock.json | 18 ++++++++++++------ package.json | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/jest.config.js b/jest.config.js index 00947398..08ef8c31 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,6 +6,9 @@ module.exports = { preset: "@vue/cli-plugin-unit-jest", transform: { "^.+\\.vue$": "@vue/vue3-jest" }, moduleFileExtensions: ["js", "vue"], + moduleNameMapper: { + axios: 'axios/dist/browser/axios.cjs' + }, collectCoverageFrom: [ "src/**/*.{js,vue}", "!src/main.js", diff --git a/package-lock.json b/package-lock.json index 38bbeaa3..f03924b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "digitalconsumer.iss", "version": "0.1.0", "dependencies": { - "axios": "^0.27.2", + "axios": "^1.4.0", "bootstrap": "^5.3", "maska": "^1.5.0", "pinia": "^2.1.4", @@ -5372,12 +5372,13 @@ } }, "node_modules/axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", "dependencies": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/axios/node_modules/form-data": { @@ -15197,6 +15198,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", diff --git a/package.json b/package.json index c100b7d1..d005f44e 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "test:unit:lite": "vue-cli-service test:unit --ci" }, "dependencies": { - "axios": "^0.27.2", + "axios": "^1.4.0", "bootstrap": "^5.3", "maska": "^1.5.0", "pinia": "^2.1.4", From 24365dc4ac8260807867a9404d73ec8f2fd17bed Mon Sep 17 00:00:00 2001 From: DavidAtSafelite Date: Wed, 9 Aug 2023 07:36:54 -0400 Subject: [PATCH 011/674] Additional package updates --- package-lock.json | 961 ++++++++++++++++++++++++++++++---------------- package.json | 10 +- 2 files changed, 643 insertions(+), 328 deletions(-) diff --git a/package-lock.json b/package-lock.json index f03924b9..ed52c13d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "axios": "^1.4.0", + "axios-retry": "^3.5.0", "bootstrap": "^5.3", "maska": "^1.5.0", "pinia": "^2.1.4", @@ -20,6 +21,7 @@ }, "devDependencies": { "@pinia/testing": "0.1.2", + "@rushstack/eslint-patch": "^1.3.2", "@testing-library/jest-dom": "5.16.5", "@testing-library/user-event": "14.4.3", "@testing-library/vue": "6.6.1", @@ -27,10 +29,11 @@ "@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-unit-jest": "~5.0.0", "@vue/cli-service": "~5.0.0", - "@vue/test-utils": "^2.0.0-0", + "@vue/test-utils": "^2.4.1", "@vue/vue3-jest": "^27.0.0-alpha.1", + "axios-mock-adapter": "^1.21.5", "babel-jest": "^27.0.6", - "eslint": "8.29.0", + "eslint": "8.45.0", "eslint-config-airbnb-base": "15.0.0", "eslint-import-resolver-alias": "1.1.2", "eslint-plugin-import": "2.26.0", @@ -40,7 +43,17 @@ "jsdoc": "^4.0.2", "sass": "^1.32.7", "sass-loader": "^12.0.0", - "vitest": "^0.32.4" + "vitest": "^0.33.0", + "volar-service-vetur": "latest" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@achrinza/node-ipc": { @@ -1712,7 +1725,6 @@ "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -1776,9 +1788,9 @@ "dev": true }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -1792,9 +1804,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -1808,9 +1820,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -1824,9 +1836,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -1840,9 +1852,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -1856,9 +1868,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -1872,9 +1884,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -1888,9 +1900,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -1904,9 +1916,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -1920,9 +1932,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -1936,9 +1948,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -1952,9 +1964,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -1968,9 +1980,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -1984,9 +1996,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -2000,9 +2012,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -2016,9 +2028,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -2032,9 +2044,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ "x64" ], @@ -2048,9 +2060,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], @@ -2064,9 +2076,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ "x64" ], @@ -2080,9 +2092,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ "arm64" ], @@ -2096,9 +2108,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ "ia32" ], @@ -2112,9 +2124,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -2142,16 +2154,25 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/regexpp": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -2172,9 +2193,9 @@ "dev": true }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2210,6 +2231,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -2226,9 +2256,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -3020,6 +3050,12 @@ "node": ">= 8" } }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true + }, "node_modules/@pinia/testing": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@pinia/testing/-/testing-0.1.2.tgz", @@ -3077,6 +3113,12 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.3.tgz", + "integrity": "sha512-0xd7qez0AQ+MbHatZTlI1gu5vkG8r7MYRUJAHPAHJBmGLs16zpkrpAVLvjQKQOqaXPDUBwOiJzNc00znHSCVBw==", + "dev": true + }, "node_modules/@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -3815,13 +3857,13 @@ "dev": true }, "node_modules/@vitest/expect": { - "version": "0.32.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.4.tgz", - "integrity": "sha512-m7EPUqmGIwIeoU763N+ivkFjTzbaBn0n9evsTOcde03ugy2avPs3kZbYmw3DkcH1j5mxhMhdamJkLQ6dM1bk/A==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.33.0.tgz", + "integrity": "sha512-sVNf+Gla3mhTCxNJx+wJLDPp/WcstOe0Ksqz4Vec51MmgMth/ia0MGFEkIZmVGeTL5HtjYR4Wl/ZxBxBXZJTzQ==", "dev": true, "dependencies": { - "@vitest/spy": "0.32.4", - "@vitest/utils": "0.32.4", + "@vitest/spy": "0.33.0", + "@vitest/utils": "0.33.0", "chai": "^4.3.7" }, "funding": { @@ -3829,12 +3871,12 @@ } }, "node_modules/@vitest/runner": { - "version": "0.32.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.4.tgz", - "integrity": "sha512-cHOVCkiRazobgdKLnczmz2oaKK9GJOw6ZyRcaPdssO1ej+wzHVIkWiCiNacb3TTYPdzMddYkCgMjZ4r8C0JFCw==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.33.0.tgz", + "integrity": "sha512-UPfACnmCB6HKRHTlcgCoBh6ppl6fDn+J/xR8dTufWiKt/74Y9bHci5CKB8tESSV82zKYtkBJo9whU3mNvfaisg==", "dev": true, "dependencies": { - "@vitest/utils": "0.32.4", + "@vitest/utils": "0.33.0", "p-limit": "^4.0.0", "pathe": "^1.1.1" }, @@ -3870,12 +3912,12 @@ } }, "node_modules/@vitest/snapshot": { - "version": "0.32.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.32.4.tgz", - "integrity": "sha512-IRpyqn9t14uqsFlVI2d7DFMImGMs1Q9218of40bdQQgMePwVdmix33yMNnebXcTzDU5eiV3eUsoxxH5v0x/IQA==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.33.0.tgz", + "integrity": "sha512-tJjrl//qAHbyHajpFvr8Wsk8DIOODEebTu7pgBrP07iOepR5jYkLFiqLq2Ltxv+r0uptUb4izv1J8XBOwKkVYA==", "dev": true, "dependencies": { - "magic-string": "^0.30.0", + "magic-string": "^0.30.1", "pathe": "^1.1.1", "pretty-format": "^29.5.0" }, @@ -3884,21 +3926,21 @@ } }, "node_modules/@vitest/snapshot/node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "version": "29.6.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz", + "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==", "dev": true, "dependencies": { - "@sinclair/typebox": "^0.25.16" + "@sinclair/typebox": "^0.27.8" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@vitest/snapshot/node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, "node_modules/@vitest/snapshot/node_modules/ansi-styles": { @@ -3914,12 +3956,12 @@ } }, "node_modules/@vitest/snapshot/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", + "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.3", + "@jest/schemas": "^29.6.0", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3934,9 +3976,9 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "0.32.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.4.tgz", - "integrity": "sha512-oA7rCOqVOOpE6rEoXuCOADX7Lla1LIa4hljI2MSccbpec54q+oifhziZIJXxlE/CvI2E+ElhBHzVu0VEvJGQKQ==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.33.0.tgz", + "integrity": "sha512-Kv+yZ4hnH1WdiAkPUQTpRxW8kGtH8VRTnus7ZTGovFYM1ZezJpvGtb9nPIjPnptHbsyIAxYZsEpVPYgtpjGnrg==", "dev": true, "dependencies": { "tinyspy": "^2.1.1" @@ -3946,9 +3988,9 @@ } }, "node_modules/@vitest/utils": { - "version": "0.32.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.4.tgz", - "integrity": "sha512-Gwnl8dhd1uJ+HXrYyV0eRqfmk9ek1ASE/LWfTCuWMw+d07ogHqp4hEAV28NiecimK6UY9DpSEPh+pXBA5gtTBg==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.33.0.tgz", + "integrity": "sha512-pF1w22ic965sv+EN6uoePkAOTkAPWM03Ri/jXNyMIKBb/XHLDPfhLvf/Fa9g0YECevAIz56oVYXhodLvLQ/awA==", "dev": true, "dependencies": { "diff-sequences": "^29.4.3", @@ -3960,21 +4002,21 @@ } }, "node_modules/@vitest/utils/node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "version": "29.6.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz", + "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==", "dev": true, "dependencies": { - "@sinclair/typebox": "^0.25.16" + "@sinclair/typebox": "^0.27.8" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@vitest/utils/node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, "node_modules/@vitest/utils/node_modules/ansi-styles": { @@ -3999,12 +4041,12 @@ } }, "node_modules/@vitest/utils/node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", + "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.3", + "@jest/schemas": "^29.6.0", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -4018,6 +4060,12 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/@vscode/l10n": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.14.tgz", + "integrity": "sha512-/yrv59IEnmh655z1oeDnGcvMYwnEzNzHLgeYcQCkhYX0xBvYWrAuefoiLcPBUkMpJsb46bqQ6Yv4pwTTQ4d3Qg==", + "dev": true + }, "node_modules/@vue/babel-helper-vue-jsx-merge-props": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", @@ -4726,12 +4774,22 @@ "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" }, "node_modules/@vue/test-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.0.2.tgz", - "integrity": "sha512-E2P4oXSaWDqTZNbmKZFVLrNN/siVN78YkEqs7pHryWerrlZR9bBFLWdJwRoguX45Ru6HxIflzKl4vQvwRMwm5g==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.1.tgz", + "integrity": "sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==", "dev": true, + "dependencies": { + "js-beautify": "1.14.9", + "vue-component-type-helpers": "1.8.4" + }, "peerDependencies": { + "@vue/server-renderer": "^3.0.1", "vue": "^3.0.1" + }, + "peerDependenciesMeta": { + "@vue/server-renderer": { + "optional": true + } } }, "node_modules/@vue/vue3-jest": { @@ -5381,6 +5439,51 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/axios-mock-adapter": { + "version": "1.21.5", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.21.5.tgz", + "integrity": "sha512-5NI1V/VK+8+JeTF8niqOowuysA4b8mGzdlMN/QnTnoXbYh4HZSNiopsDclN2g/m85+G++IrEtUdZaQ3GnaMsSA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.5" + }, + "peerDependencies": { + "axios": ">= 0.17.0" + } + }, + "node_modules/axios-mock-adapter/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/axios-retry": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.6.0.tgz", + "integrity": "sha512-jtH4qWTKZ2a17dH6tjq52Y1ssNV0lKge6/Z9Lw67s9Wt01nGTg4hg7/LJBGYfDci44NTANJQlCPHPOT/TSFm9w==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "is-retry-allowed": "^2.2.0" + } + }, "node_modules/axios/node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -5901,6 +6004,15 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -6050,6 +6162,15 @@ "node": ">=10" } }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "dev": true, + "dependencies": { + "is-regex": "^1.0.3" + } + }, "node_modules/check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -7262,6 +7383,15 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", @@ -7445,51 +7575,71 @@ } }, "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", "dev": true, "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" }, "bin": { "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/editorconfig/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } }, - "node_modules/editorconfig/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", "dev": true, "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/editorconfig/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -7684,9 +7834,9 @@ } }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -7696,28 +7846,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/escalade": { @@ -7767,13 +7917,16 @@ } }, "node_modules/eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", + "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -7782,34 +7935,29 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -8019,40 +8167,16 @@ "node": ">=4.0" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-styles": { @@ -8137,9 +8261,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -8147,6 +8271,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/find-up": { @@ -8166,9 +8293,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -8230,17 +8357,17 @@ } }, "node_modules/eslint/node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -8367,14 +8494,14 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -8397,9 +8524,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -9117,10 +9244,10 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/gzip-size": { @@ -9768,6 +9895,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-expression/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -9934,6 +10083,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-set": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", @@ -12545,14 +12705,14 @@ } }, "node_modules/js-beautify": { - "version": "1.14.6", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.6.tgz", - "integrity": "sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==", + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.9.tgz", + "integrity": "sha512-coM7xq1syLcMyuVGyToxcj2AlzhkDjmfklL8r0JgJ7A76wyGMpJ1oA35mr4APdYNO/o/4YY8H54NQIJzhMbhBg==", "dev": true, "dependencies": { "config-chain": "^1.1.13", - "editorconfig": "^0.15.3", - "glob": "^8.0.3", + "editorconfig": "^1.0.3", + "glob": "^8.1.0", "nopt": "^6.0.0" }, "bin": { @@ -12561,7 +12721,7 @@ "js-beautify": "js/bin/js-beautify.js" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/js-beautify/node_modules/brace-expansion": { @@ -12574,9 +12734,9 @@ } }, "node_modules/js-beautify/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -12593,9 +12753,9 @@ } }, "node_modules/js-beautify/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -12613,16 +12773,6 @@ "node": ">=0.6.0" } }, - "node_modules/js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -14513,9 +14663,9 @@ } }, "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", + "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", "funding": [ { "type": "opencollective", @@ -15069,11 +15219,10 @@ } }, "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, - "optional": true, "bin": { "prettier": "bin-prettier.js" }, @@ -15215,6 +15364,23 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, + "node_modules/pug-error": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==", + "dev": true + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dev": true, + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -15433,8 +15599,7 @@ "node_modules/regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "node_modules/regenerator-transform": { "version": "0.15.0", @@ -15462,18 +15627,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/regexpu-core": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", @@ -15668,9 +15821,9 @@ } }, "node_modules/rollup": { - "version": "3.26.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.0.tgz", - "integrity": "sha512-YzJH0eunH2hr3knvF3i6IkLO/jTjAEwU4HoMUbQl4//Tnl3ou0e7P5SjxdDr8HQJdeUJShlbEHXrrnEHy1l7Yg==", + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", + "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -16065,12 +16218,6 @@ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", - "dev": true - }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -16734,9 +16881,9 @@ "dev": true }, "node_modules/tinypool": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", - "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.6.0.tgz", + "integrity": "sha512-FdswUUo5SxRizcBc6b1GSuLpLjisa8N8qMyYoP3rl+bym+QauhtJP5bvZY1ytt8krKGmMLYIRl36HBZfeAoqhQ==", "dev": true, "engines": { "node": ">=14.0.0" @@ -16901,6 +17048,76 @@ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tslint/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -16956,6 +17173,19 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -16963,9 +17193,9 @@ "dev": true }, "node_modules/ufo": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.1.2.tgz", - "integrity": "sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.2.0.tgz", + "integrity": "sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==", "dev": true }, "node_modules/unbox-primitive": { @@ -17176,14 +17406,14 @@ } }, "node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", + "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -17191,12 +17421,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -17209,6 +17443,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -17224,9 +17461,9 @@ } }, "node_modules/vite-node": { - "version": "0.32.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.4.tgz", - "integrity": "sha512-L2gIw+dCxO0LK14QnUMoqSYpa9XRGnTTTDjW2h19Mr+GR0EFj4vx52W41gFXfMLqpA00eK4ZjOVYo1Xk//LFEw==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.33.0.tgz", + "integrity": "sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -17247,34 +17484,34 @@ } }, "node_modules/vitest": { - "version": "0.32.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.4.tgz", - "integrity": "sha512-3czFm8RnrsWwIzVDu/Ca48Y/M+qh3vOnF16czJm98Q/AN1y3B6PBsyV8Re91Ty5s7txKNjEhpgtGPcfdbh2MZg==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.33.0.tgz", + "integrity": "sha512-1CxaugJ50xskkQ0e969R/hW47za4YXDUfWJDxip1hwbnhUjYolpfUn2AMOulqG/Dtd9WYAtkHmM/m3yKVrEejQ==", "dev": true, "dependencies": { "@types/chai": "^4.3.5", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.32.4", - "@vitest/runner": "0.32.4", - "@vitest/snapshot": "0.32.4", - "@vitest/spy": "0.32.4", - "@vitest/utils": "0.32.4", + "@vitest/expect": "0.33.0", + "@vitest/runner": "0.33.0", + "@vitest/snapshot": "0.33.0", + "@vitest/spy": "0.33.0", + "@vitest/utils": "0.33.0", "acorn": "^8.9.0", "acorn-walk": "^8.2.0", "cac": "^6.7.14", "chai": "^4.3.7", "debug": "^4.3.4", "local-pkg": "^0.4.3", - "magic-string": "^0.30.0", + "magic-string": "^0.30.1", "pathe": "^1.1.1", "picocolors": "^1.0.0", "std-env": "^3.3.3", "strip-literal": "^1.0.1", "tinybench": "^2.5.0", - "tinypool": "^0.5.0", + "tinypool": "^0.6.0", "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.32.4", + "vite-node": "0.33.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -17323,6 +17560,74 @@ } } }, + "node_modules/vls": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/vls/-/vls-0.8.5.tgz", + "integrity": "sha512-61kbdO2COZWBMC4wq59QfDdev9ruXd0226f57DFJTFpFXv85S+qnHakQlAmbSYFFLGKcx95HB2UjnuQh4YRwFA==", + "dev": true, + "dependencies": { + "eslint": "^8.34.0", + "eslint-plugin-vue": "^9.9.0", + "prettier": "^2.8.4", + "pug-lexer": "^5.0.1", + "tslint": "6.1.3", + "typescript": "^4.9.5" + }, + "bin": { + "vls": "bin/vls" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/volar-service-vetur": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/volar-service-vetur/-/volar-service-vetur-0.0.11.tgz", + "integrity": "sha512-ahjOhXZmIZESMLWKrmxyhZvyvC3niSm0gjmSnZquy+UXHPSqHW0I2JVMTCQ2gB26ZadE2D8Kao7UbcgphSB+8w==", + "dev": true, + "dependencies": { + "vls": "^0.8.2", + "vscode-html-languageservice": "^5.0.4" + }, + "peerDependencies": { + "@volar/language-service": "~1.10.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } + } + }, + "node_modules/vscode-html-languageservice": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.0.6.tgz", + "integrity": "sha512-gCixNg6fjPO7+kwSMBAVXcwDRHdjz1WOyNfI0n5Wx0J7dfHG8ggb3zD1FI8E2daTZrwS1cooOiSoc1Xxph4qRQ==", + "dev": true, + "dependencies": { + "@vscode/l10n": "^0.0.14", + "vscode-languageserver-textdocument": "^1.0.8", + "vscode-languageserver-types": "^3.17.3", + "vscode-uri": "^3.0.7" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", + "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==", + "dev": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.3", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz", + "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==", + "dev": true + }, + "node_modules/vscode-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.7.tgz", + "integrity": "sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==", + "dev": true + }, "node_modules/vue": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz", @@ -17335,6 +17640,12 @@ "@vue/shared": "3.3.4" } }, + "node_modules/vue-component-type-helpers": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-1.8.4.tgz", + "integrity": "sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==", + "dev": true + }, "node_modules/vue-eslint-parser": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz", diff --git a/package.json b/package.json index d005f44e..2cd66185 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "axios": "^1.4.0", + "axios-retry": "^3.5.0", "bootstrap": "^5.3", "maska": "^1.5.0", "pinia": "^2.1.4", @@ -26,6 +27,7 @@ "vue-router": "4.2.4" }, "devDependencies": { + "@rushstack/eslint-patch": "^1.3.2", "@pinia/testing": "0.1.2", "@testing-library/jest-dom": "5.16.5", "@testing-library/user-event": "14.4.3", @@ -34,10 +36,11 @@ "@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-unit-jest": "~5.0.0", "@vue/cli-service": "~5.0.0", - "@vue/test-utils": "^2.0.0-0", + "@vue/test-utils": "^2.4.1", "@vue/vue3-jest": "^27.0.0-alpha.1", + "axios-mock-adapter": "^1.21.5", "babel-jest": "^27.0.6", - "eslint": "8.29.0", + "eslint": "8.45.0", "eslint-config-airbnb-base": "15.0.0", "eslint-import-resolver-alias": "1.1.2", "eslint-plugin-import": "2.26.0", @@ -47,6 +50,7 @@ "jsdoc": "^4.0.2", "sass": "^1.32.7", "sass-loader": "^12.0.0", - "vitest": "^0.32.4" + "vitest": "^0.33.0", + "volar-service-vetur": "latest" } } From 2bc489957335968b3567400db434e53bf1b503f1 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 8 Aug 2023 14:42:01 -0400 Subject: [PATCH 012/674] updates to match fmg --- package-lock.json | 10 ++--- package.json | 2 +- .../textbox-question/textbox-question.vue | 39 ++++++++----------- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed52c13d..0cb678b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "maska": "^1.5.0", "pinia": "^2.1.4", "pinia-plugin-persistedstate": "^2.2.0", - "vee-validate": "^4.7.0", + "vee-validate": "^4.5.7", "vue": "^3.3.4", "vue-plugin-load-script": "^2.1.0", "vue-router": "4.2.4" @@ -17395,11 +17395,11 @@ } }, "node_modules/vee-validate": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.7.0.tgz", - "integrity": "sha512-7HW2RE8mWaT57Jn+JU7jwczFqtlc1rIAwSbp8kD1L2sO0plhT9YeDNKW5iaI9baosc4h+iyb6itMlXtqAAqAfw==", + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.5.7.tgz", + "integrity": "sha512-EcpvOikBP5LlRIKwULfwRDeyIaERuOJztZUPWRmSIeWpeQWD6hs9qQ8A3CmVVteqEohbUM07gV/ea8lPXCfCJQ==", "dependencies": { - "@vue/devtools-api": "^6.1.4" + "@vue/devtools-api": "^6.0.0-beta.15" }, "peerDependencies": { "vue": "^3.0.0" diff --git a/package.json b/package.json index 2cd66185..c2b38169 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "maska": "^1.5.0", "pinia": "^2.1.4", "pinia-plugin-persistedstate": "^2.2.0", - "vee-validate": "^4.7.0", + "vee-validate": "^4.5.7", "vue": "^3.3.4", "vue-plugin-load-script": "^2.1.0", "vue-router": "4.2.4" diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index a2e8c80c..ea4f1cf9 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -1,7 +1,5 @@ @@ -116,12 +107,12 @@ export default { let initialValue; switch (typeof modelValue) { - case 'number': - initialValue = modelValue; - break; - default: - initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; - break; + case 'number': + initialValue = modelValue; + break; + default: + initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; + break; } const fieldOptions = { @@ -131,9 +122,11 @@ export default { }; // eslint-disable-next-line no-shadow - const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField(props.inputId, + const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField( + props.inputId, props.validationRules, - fieldOptions); + fieldOptions + ); return { errorMessage, From 3037b43a88924f7af41931675bf0c21705c12ee2 Mon Sep 17 00:00:00 2001 From: DavidAtSafelite Date: Wed, 9 Aug 2023 11:19:41 -0400 Subject: [PATCH 013/674] prefer default - initial attemp - application-config --- src/constants/analytics.js | 24 +++++++++---------- src/constants/application-config.js | 2 +- src/constants/cookie-names.js | 2 +- src/global-methods.js | 2 +- src/helpers/cookie-helper.js | 2 +- src/helpers/session-helper.js | 2 +- src/helpers/session-helper.spec.js | 2 +- .../address-questions/address-questions.vue | 2 +- .../vehicle-parts/vehicle-parts.spec.js | 2 +- src/layouts/welcome-page/welcome-page.spec.js | 2 +- src/router/index.js | 2 +- src/store/index.js | 2 +- src/ux-components/alert/alert.vue | 2 +- 13 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/constants/analytics.js b/src/constants/analytics.js index 2edbd9a0..c0171209 100644 --- a/src/constants/analytics.js +++ b/src/constants/analytics.js @@ -1,36 +1,36 @@ -const analyticsPageEvents = { +const analyticsPageEvents = Object.freeze({ ENTRY: 'ENTRY', EVENT: 'EVENT' -}; +}); // GA Constants -const GaEvents = { +const GaEvents = Object.freeze({ GENERIC_EVENT: 'event', PAGE_VIEW_EVENT: 'logPageview' -}; +}); -const GaCategories = { +const GaCategories = Object.freeze({ API_RESPONSE: 'Api_Response', EVOX: 'Evox' -}; +}); -const GaActions = { +const GaActions = Object.freeze({ RESULT: 'Result', CLICKED: 'Clicked', VIF: 'vif', SUBMITTED: 'Submitted' -}; +}); -const GaLabels = { +const GaLabels = Object.freeze({ SUCCESS: 'Success', ERROR: 'Error', LICENSE_PLATE_LOOKUP: 'License_Plate_Look_Up', VIN_LOOKUP: 'Vin_Look_Up', ADDRESS_LOOKUP: 'Address_Look_up' -}; +}); -const ValueToLogTypes = { +const ValueToLogTypes = Object.freeze({ LAST_5: 'last_5' -}; +}); export { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents, ValueToLogTypes }; diff --git a/src/constants/application-config.js b/src/constants/application-config.js index 9dbc7ac3..5f67e3fd 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -14,4 +14,4 @@ const applicationConfig = { CASH_PARENT_ACCOUNT_NUMBER: 167132 }; -export { applicationConfig }; \ No newline at end of file +export default Object.freeze(applicationConfig); diff --git a/src/constants/cookie-names.js b/src/constants/cookie-names.js index 64fc6091..3a7606e3 100644 --- a/src/constants/cookie-names.js +++ b/src/constants/cookie-names.js @@ -1,4 +1,4 @@ -import { applicationConfig } from '@/constants/application-config.js'; +import applicationConfig from '@/constants/application-config.js'; const cookieNames = { ISS_SESSION_INFO: `ISSSessionInfo-${applicationConfig.CURRENT_ENVIRONMENT}`, diff --git a/src/global-methods.js b/src/global-methods.js index 141e4c34..779d53dc 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -2,7 +2,7 @@ import axios from 'axios'; import analyticsMixIn from '@/mixins/analytics-mixin.js'; import { useMainStore } from '@/store'; -import { applicationConfig } from '@/constants/application-config.js'; +import applicationConfig from '@/constants/application-config.js'; import { GaCategories, GaActions, GaLabels } from '@/constants/analytics'; import { headerKeys } from '@/constants/header-keys'; diff --git a/src/helpers/cookie-helper.js b/src/helpers/cookie-helper.js index e4abd6a7..123c9ec3 100644 --- a/src/helpers/cookie-helper.js +++ b/src/helpers/cookie-helper.js @@ -1,5 +1,5 @@ import { cookieNames } from '@/constants/cookie-names'; -import { applicationConfig } from '@/constants/application-config'; +import applicationConfig from '@/constants/application-config'; import { useMainStore } from '@/store'; /* diff --git a/src/helpers/session-helper.js b/src/helpers/session-helper.js index c6b57dff..a82e1618 100644 --- a/src/helpers/session-helper.js +++ b/src/helpers/session-helper.js @@ -1,4 +1,4 @@ -import { applicationConfig } from '@/constants/application-config'; +import applicationConfig from '@/constants/application-config'; import { getISSCookie } from '@/helpers/cookie-helper.js'; /* diff --git a/src/helpers/session-helper.spec.js b/src/helpers/session-helper.spec.js index cefc0cc2..ca9725ab 100644 --- a/src/helpers/session-helper.spec.js +++ b/src/helpers/session-helper.spec.js @@ -4,7 +4,7 @@ import { isSavedSessionStillActive, getDateForSavedSessionTimeout } from '@/helpers/session-helper'; -import { applicationConfig } from '@/constants/application-config'; +import applicationConfig from '@/constants/application-config'; describe('isAnalyticsSessionStillActive', () => { test('isAnalyticsSessionStillActive, should return true', () => { diff --git a/src/iss-components/address-questions/address-questions.vue b/src/iss-components/address-questions/address-questions.vue index ca89447a..0ae33166 100644 --- a/src/iss-components/address-questions/address-questions.vue +++ b/src/iss-components/address-questions/address-questions.vue @@ -92,7 +92,7 @@ import textboxQuestion from '@/digital-components/textbox-question/textbox-question'; import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question'; import alert from '@/ux-components/alert/alert'; -import { applicationConfig } from '@/constants/application-config.js'; +import applicationConfig from '@/constants/application-config.js'; import { defineRule } from 'vee-validate'; import { required, regex } from '@/helpers/validation-rules'; import { errorMessages } from '@/constants/error-messages'; diff --git a/src/layouts/vehicle-parts/vehicle-parts.spec.js b/src/layouts/vehicle-parts/vehicle-parts.spec.js index 1a89058d..769da959 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.spec.js +++ b/src/layouts/vehicle-parts/vehicle-parts.spec.js @@ -11,7 +11,7 @@ import { nextTick } from 'vue'; import baseMixin from '@/mixins/base-mixin.js'; import { useMainStore } from '@/store'; import { navigationScenarios } from '@/router/router-constants/navigation-scenarios'; -import { applicationConfig } from '@/constants/application-config'; +import applicationConfig from '@/constants/application-config'; // Mock our module for promises. jest.mock('@/helpers/layout-helper.js', () => ({ diff --git a/src/layouts/welcome-page/welcome-page.spec.js b/src/layouts/welcome-page/welcome-page.spec.js index 8b0bbcdd..b66528fa 100644 --- a/src/layouts/welcome-page/welcome-page.spec.js +++ b/src/layouts/welcome-page/welcome-page.spec.js @@ -7,7 +7,7 @@ import { settleAllPromises } from '@/helpers/layout-helper.js'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import baseMixin from '@/mixins/base-mixin.js'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; -import { applicationConfig } from '@/constants/application-config'; +import applicationConfig from '@/constants/application-config'; import { useMainStore } from '@/store'; import { navigationScenarios } from '@/router/router-constants/navigation-scenarios'; diff --git a/src/router/index.js b/src/router/index.js index c27b55bb..fdc1fc02 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -12,7 +12,7 @@ import { updateSessionIdCookie } from '@/helpers/cookie-helper'; import { experimentTriggers } from '@/constants/experiments'; -import { applicationConfig } from '@/constants/application-config'; +import applicationConfig from '@/constants/application-config'; import analyticsMixin from '@/mixins/analytics-mixin'; import { navigationScenarios } from './router-constants/navigation-scenarios'; diff --git a/src/store/index.js b/src/store/index.js index 5b0f9f15..383ac713 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -6,7 +6,7 @@ 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 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'; diff --git a/src/ux-components/alert/alert.vue b/src/ux-components/alert/alert.vue index 8ec4a76c..092d2d84 100644 --- a/src/ux-components/alert/alert.vue +++ b/src/ux-components/alert/alert.vue @@ -60,7 +60,7 @@ import { getRouterLinkDisplayTextFromCopy, splitCMSCopyOnParagraphTag } from '@/helpers/cms-content-helper'; -import { applicationConfig } from '@/constants/application-config'; +import applicationConfig from '@/constants/application-config'; export default { name: 'alert', From b58ccce95ef53bc4114610b1f47272b26f8a5263 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Wed, 9 Aug 2023 11:48:44 -0400 Subject: [PATCH 014/674] error handling- ensures policyLookupSuccessful is set to false for failed policy lookups --- src/store/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/store/index.js b/src/store/index.js index 5b0f9f15..d91b152e 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -345,6 +345,9 @@ export const useMainStore = defineStore({ const responsePolicy = r.data.policies?.[0]; policy.policyLookupSuccessful = !!responsePolicy; return r; + }, (r) => { + policy.policyLookupSuccessful = false; + return r; }); return response; } catch (responseError) { From 65c9ce64c24100322e861a1bcdecc2ddf5a1ee9d Mon Sep 17 00:00:00 2001 From: DavidAtSafelite Date: Thu, 10 Aug 2023 07:33:38 -0400 Subject: [PATCH 015/674] A bit more prefer-default and I added the new store constants. They are *not* being used yet, but I like the idea of getting them in and giving folks an opportunity to get used to the idea. --- src/constants/cookie-names.js | 2 +- src/constants/coverage-statuses.js | 6 +- src/constants/damage-locations-cms.js | 6 +- src/constants/damage-locations-selected.js | 6 +- src/helpers/cookie-helper.js | 2 +- src/helpers/damage-helper.js | 2 +- src/helpers/unit-test-helper.js | 2 +- .../service-package-question.vue | 3 +- .../side-door-options/side-door-options.vue | 2 +- src/layouts/vehicle-damage/vehicle-damage.vue | 4 +- .../windshield-options/windshield-options.vue | 2 +- src/mixins/analytics-mixin.js | 2 +- src/store/constants/apis.js | 191 +++++++++++++ src/store/constants/default-payloads.js | 254 ++++++++++++++++++ src/store/index.js | 4 +- src/store/store.spec.js | 2 +- 16 files changed, 468 insertions(+), 22 deletions(-) create mode 100644 src/store/constants/apis.js create mode 100644 src/store/constants/default-payloads.js diff --git a/src/constants/cookie-names.js b/src/constants/cookie-names.js index 3a7606e3..ded5da72 100644 --- a/src/constants/cookie-names.js +++ b/src/constants/cookie-names.js @@ -9,4 +9,4 @@ const cookieNames = { SESSION_KEY: 'skey' }; -export { cookieNames }; +export default Object.freeze(cookieNames); diff --git a/src/constants/coverage-statuses.js b/src/constants/coverage-statuses.js index 7b50aa51..5f794cc9 100644 --- a/src/constants/coverage-statuses.js +++ b/src/constants/coverage-statuses.js @@ -1,7 +1,7 @@ -const coverageStatuses = { +const coverageStatuses = Object.freeze({ PENDING: 'Pending', NO_COMP: 'No Comp', VERIFIED: 'Verified' -}; +}); -export { coverageStatuses }; \ No newline at end of file +export default coverageStatuses; diff --git a/src/constants/damage-locations-cms.js b/src/constants/damage-locations-cms.js index 8fd10043..9b99dc68 100644 --- a/src/constants/damage-locations-cms.js +++ b/src/constants/damage-locations-cms.js @@ -1,9 +1,9 @@ -const damageLocationsCms = { +const damageLocationsCms = Object.freeze({ WINDSHIELD: 'WINDSHIELD', SIDEDOOR: 'SIDEDOOR', REARWINDOW: 'REARWINDOW', DRIVERSIDE: 'DRIVERSIDE', PASSENGERSIDE: 'PASSENGERSIDE' -}; +}); -export { damageLocationsCms }; +export default damageLocationsCms; diff --git a/src/constants/damage-locations-selected.js b/src/constants/damage-locations-selected.js index a57dbd88..2783283c 100644 --- a/src/constants/damage-locations-selected.js +++ b/src/constants/damage-locations-selected.js @@ -1,4 +1,4 @@ -const damageLocationsSelected = { +const damageLocationsSelected = Object.freeze({ WINDSHIELD: 'Windshield', SIDEDOOR: 'SideDoor', REARWINDOW: 'RearWindow', @@ -16,6 +16,6 @@ const damageLocationsSelected = { PASSENGERSIDE: 'PassengerSide', STATIONARY: 'Stationary', SLIDER: 'Slider' -}; +}); -export { damageLocationsSelected }; +export default damageLocationsSelected; diff --git a/src/helpers/cookie-helper.js b/src/helpers/cookie-helper.js index 123c9ec3..b52051e9 100644 --- a/src/helpers/cookie-helper.js +++ b/src/helpers/cookie-helper.js @@ -1,4 +1,4 @@ -import { cookieNames } from '@/constants/cookie-names'; +import cookieNames from '@/constants/cookie-names'; import applicationConfig from '@/constants/application-config'; import { useMainStore } from '@/store'; diff --git a/src/helpers/damage-helper.js b/src/helpers/damage-helper.js index 9bb91f5a..3c6bfce2 100644 --- a/src/helpers/damage-helper.js +++ b/src/helpers/damage-helper.js @@ -1,5 +1,5 @@ import damageCustomLabels from '@/constants/damage-custom-labels'; -import { damageLocationsSelected } from '@/constants/damage-locations-selected'; +import damageLocationsSelected from '@/constants/damage-locations-selected'; import { useMainStore } from '@/store'; export function getDamageString() { diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index cbeb6cda..01a6a286 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -2,7 +2,7 @@ import { navigationScenarios } from '@/router/router-constants/navigation-scenar import { RouterLinkStub } from '@vue/test-utils'; import { vehicleCategories } from '@/constants/vehicle-categories.js'; import { issPageValues } from '@/router/router-constants/issPage-values'; -import { cookieNames } from '@/constants/cookie-names'; +import cookieNames from '@/constants/cookie-names'; import { Form } from 'vee-validate'; import baseMixin from '@/mixins/base-mixin'; import { diff --git a/src/layouts/service-packages/service-package-question/service-package-question.vue b/src/layouts/service-packages/service-package-question/service-package-question.vue index dfd4d83e..0fc826ee 100644 --- a/src/layouts/service-packages/service-package-question/service-package-question.vue +++ b/src/layouts/service-packages/service-package-question/service-package-question.vue @@ -13,11 +13,12 @@ From 2f8eeacb20251d4e3a7c702b30939e5e3ae9c46d Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 15 Aug 2023 15:59:09 -0400 Subject: [PATCH 038/674] verified deductible styling WIP --- .../coverage-statement/coverage-statement.vue | 2 +- .../coverage-statement/recal-modal/recal-modal.vue | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 1576531c..39fcb78f 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -59,7 +59,7 @@ :isDismissible="false">
-
+
@@ -75,16 +75,17 @@ export default { From 4f5e1a09f00e21b7c096810945ad40db1f803d53 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Wed, 16 Aug 2023 11:28:59 -0400 Subject: [PATCH 044/674] styling fixes, conversion from px to rem --- .../coverage-statement/coverage-statement.vue | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 39fcb78f..4e800566 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -419,19 +419,22 @@ export default { .cost { color: $green; - font-size: 32px; + font-size: 2rem; font-weight: 300; - line-height: 44px; + line-height: 2.75rem; } .deductible-text { - line-height: 24px; + line-height: 1.5rem; } ::v-deep p { - line-height: 24px; - font-size: 14px; - margin-bottom: 8px; + line-height: 1.5rem; + font-size: 0.875rem; + margin-bottom: 0.5rem; + strong { + color: $black; + } } ::v-deep .question-text { @@ -446,9 +449,9 @@ export default { ::v-deep .deductible-modal { p { - margin-bottom: 0px !important; - font-size: 16px; - line-height: 26px; + margin-bottom: 0 !important; + font-size: 1rem; + line-height: 1.625rem; } img.mb-4 { margin: 0 !important; @@ -461,9 +464,4 @@ export default { } } -// .my-4 { -// margin-top: 8px !important; -// margin-bottom: 0px !important; -// } - From 2709cca25f672c33d1381e4606b45bd0e64aa6ef Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 16 Aug 2023 16:18:15 -0400 Subject: [PATCH 045/674] vdeep to fix scoping issue for image. --- .../provider-preference.vue | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/layouts/provider-preference/provider-preference.vue b/src/layouts/provider-preference/provider-preference.vue index 081d4b84..0c42782b 100644 --- a/src/layouts/provider-preference/provider-preference.vue +++ b/src/layouts/provider-preference/provider-preference.vue @@ -32,8 +32,8 @@
+ ref="recalModal" + cmsWidgetName="RecalModal" /> @@ -138,8 +138,7 @@ export default { buttonLabel: this.getHeaderTextFromCms(answer.cmsWidgetName), buttonLabelSubCopy: this.getSubheaderTextFromCms(answer.cmsWidgetName), buttonBodyCopy: this.getBodyTextFromCms(answer.cmsWidgetName) - } - )); + })); return modifiedAnswers; }, ackError() { @@ -158,7 +157,7 @@ export default { return headerText?.replace('{custom:SafeliteLogo}', ""); }, getSubheaderTextFromCms(cmsWidgetName) { - return this. getCmsContent(cmsWidgetName, 'SubheaderText'); + return this.getCmsContent(cmsWidgetName, 'SubheaderText'); }, getBodyTextFromCms(cmsWidgetName) { return this.getCmsContent(cmsWidgetName, 'BodyText'); @@ -183,22 +182,22 @@ export default { if (this.selectedProvider) { let scenario = null; switch (this.selectedProvider) { - case options.SAFELITE: - scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE; - break; - case options.TPA: - if (this.mainStore.issConfig.enableTPAFlow) { - if (this.mainStore.hasRecalibrationPart) { - this.$refs.TPARecalModal.openModal(); - this.$refs.siteFooter.removeLoader(); - return; + case options.SAFELITE: + scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE; + break; + case options.TPA: + if (this.mainStore.issConfig.enableTPAFlow) { + if (this.mainStore.hasRecalibrationPart) { + this.$refs.TPARecalModal.openModal(); + this.$refs.siteFooter.removeLoader(); + return; + } + scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED; + } else { + scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED; } - scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED; - } else { - scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED; - } - break; - default: + break; + default: } this.navigateForward(scenario); this.mainStore.saveProviderPreferenceData({ @@ -214,25 +213,23 @@ export default { }; From e489567e5ebdd2a64be32ab0846c08f6b9a01776 Mon Sep 17 00:00:00 2001 From: DavidAtSafelite Date: Fri, 18 Aug 2023 06:37:20 -0400 Subject: [PATCH 046/674] Various linting, mostly ux-components and prefer default on issPageValues --- .../dropdown-question.spec.js | 2 +- .../dropdown-question/dropdown-question.vue | 32 +-- .../textbox-question/textbox-question.spec.js | 3 +- .../textbox-question/textbox-question.vue | 35 +-- src/helpers/clientauth-helper.js | 3 +- src/helpers/cookie-helper.js | 200 +++++++++--------- src/helpers/damage-helper.js | 1 + src/helpers/data-generation.js | 6 +- src/helpers/event-bus/event-bus.spec.js | 2 + src/helpers/global-rule-definer.js | 32 +-- src/helpers/unit-test-helper.js | 15 +- .../site-footer/site-footer.vue | 2 +- .../site-header/menu-modal/menu-modal.spec.js | 2 +- .../site-header/menu-modal/menu-modal.vue | 2 +- .../site-header/site-header.spec.js | 4 +- .../site-header/site-header.vue | 4 +- .../button-back/button-back.spec.js | 2 +- .../site-sub-header/site-sub-header.spec.js | 2 +- .../site-sub-header/site-sub-header.vue | 22 +- .../steering-text/steering-text.spec.js | 4 +- .../address-vehicles/address-vehicles.vue | 2 +- .../bailout-confirmation.vue | 6 +- .../capability-questions.vue | 4 +- src/layouts/entry-page/entry-page.vue | 2 +- .../molding-questions/molding-questions.vue | 4 +- src/layouts/part-questions/part-questions.vue | 5 +- .../policy-vehicles/policy-vehicles.spec.js | 4 +- .../policy-vehicles/policy-vehicles.vue | 10 +- .../provider-preference.vue | 18 +- .../tpa-recal-toggle/tpa-recal-toggle.spec.js | 4 +- src/layouts/vehicle-parts/vehicle-parts.vue | 15 +- .../vin-location-information.spec.js | 4 +- src/layouts/vin-lookup/vin-lookup.spec.js | 4 +- src/mixins/vehicle-questions-mixin.js | 2 +- src/mixins/vehicle-questions-mixin.spec.js | 2 +- src/router/index.js | 2 +- src/router/router-constants/issPage-values.js | 6 +- src/router/router-constants/routing-table.js | 2 +- src/router/router.spec.js | 2 +- src/store/index.js | 2 +- src/ux-components/alert/alert.spec.js | 103 +++++---- src/ux-components/alert/alert.vue | 2 +- .../button-main/button-main.spec.js | 27 +-- src/ux-components/button-main/button-main.vue | 2 +- src/ux-components/checkbox/checkbox.spec.js | 2 +- .../list-button-horizontal.spec.js | 38 ++-- .../list-button-horizontal.vue | 2 +- .../list-button/list-button.spec.js | 26 +-- src/ux-components/list-button/list-button.vue | 4 +- src/ux-components/list-card/list-card.spec.js | 2 +- src/ux-components/list-card/list-card.vue | 2 +- .../modal-button-main.spec.js | 24 +-- .../modal-button-main/modal-button-main.vue | 2 +- src/ux-components/radio/radio.spec.js | 2 +- src/ux-components/text-link/text-link.spec.js | 2 +- 55 files changed, 345 insertions(+), 370 deletions(-) diff --git a/src/digital-components/dropdown-question/dropdown-question.spec.js b/src/digital-components/dropdown-question/dropdown-question.spec.js index 309f8477..a45217bc 100644 --- a/src/digital-components/dropdown-question/dropdown-question.spec.js +++ b/src/digital-components/dropdown-question/dropdown-question.spec.js @@ -154,6 +154,6 @@ describe('dropdownQuestion.vue', () => { wrapper.vm.$options.watch.selectedOption.call(wrapper.vm, 1); // Assert - expect(wrapper.vm.handleChange).toHaveBeenCalled; + expect(wrapper.vm.handleChange).toHaveBeenCalled(); }); }); diff --git a/src/digital-components/dropdown-question/dropdown-question.vue b/src/digital-components/dropdown-question/dropdown-question.vue index cbca8c8f..09504e4a 100644 --- a/src/digital-components/dropdown-question/dropdown-question.vue +++ b/src/digital-components/dropdown-question/dropdown-question.vue @@ -17,14 +17,22 @@ :aria-required="isRequired" :validationRules="validationRules" :placeHolderText="placeHolderText"> - - -
+
{{ errorMessage }}
@@ -57,12 +65,12 @@ export default { let initialValue; switch (typeof modelValue) { - case 'number': - initialValue = modelValue; - break; - default: - initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; - break; + case 'number': + initialValue = modelValue; + break; + default: + initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; + break; } const fieldOptions = { @@ -71,11 +79,9 @@ export default { initialValue }; - const { errorMessage, handleBlur, handleChange, meta, errors } = useField( - props.inputId, + const { errorMessage, handleBlur, handleChange, meta, errors } = useField(props.inputId, props.validationRules, - fieldOptions - ); + fieldOptions); return { errorMessage, diff --git a/src/digital-components/textbox-question/textbox-question.spec.js b/src/digital-components/textbox-question/textbox-question.spec.js index 53c61a1b..c98e7837 100644 --- a/src/digital-components/textbox-question/textbox-question.spec.js +++ b/src/digital-components/textbox-question/textbox-question.spec.js @@ -129,7 +129,8 @@ describe('textboxQuestion.vue', () => { expect(wrapper.emitted()).toHaveProperty('change'); }); - it('Should call this.handleChange with new value when the value is changed and the new value is valid', async () => { + // TODO Correct test so it actually calls toHaveBeenCalled -> () <- + it.skip('Should call this.handleChange with new value when the value is changed and the new value is valid', async () => { // Arrange const wrapper = shallowMount(textboxQuestion, { global: { diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 21453a6c..26299c87 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -1,5 +1,7 @@ @@ -107,12 +116,12 @@ export default { let initialValue; switch (typeof modelValue) { - case 'number': - initialValue = modelValue; - break; - default: - initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; - break; + case 'number': + initialValue = modelValue; + break; + default: + initialValue = modelValue && modelValue.length > 0 ? modelValue : ''; + break; } const fieldOptions = { @@ -122,11 +131,9 @@ export default { }; // eslint-disable-next-line no-shadow - const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField( - props.inputId, + const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField(props.inputId, props.validationRules, - fieldOptions - ); + fieldOptions); return { errorMessage, diff --git a/src/helpers/clientauth-helper.js b/src/helpers/clientauth-helper.js index 2466fbc9..3d1a7f58 100644 --- a/src/helpers/clientauth-helper.js +++ b/src/helpers/clientauth-helper.js @@ -7,9 +7,8 @@ const validateISSClientTag = (clientTag) => { .then((response) => // Success response, - (error) => // Error - null); + () => null); }; export default validateISSClientTag; diff --git a/src/helpers/cookie-helper.js b/src/helpers/cookie-helper.js index b52051e9..de642ec3 100644 --- a/src/helpers/cookie-helper.js +++ b/src/helpers/cookie-helper.js @@ -2,22 +2,68 @@ import cookieNames from '@/constants/cookie-names'; import applicationConfig from '@/constants/application-config'; import { useMainStore } from '@/store'; -/* - Will update the cookie if present, or create a new one if not. -*/ -export function updateOrCreateISSCookie() { - const store = useMainStore(); +function isLocalhost() { + // eslint-disable-next-line no-restricted-globals + return location.hostname.includes('localhost'); +} - // Set up cookie with all the props. - setISSCookieProperties({ - LastTouched: new Date().toUTCString(), - SavedSessionTimeoutDate: store.applicationUser.savedSessionTimeout, - ShouldResetState: false, - ReferralNumber: store.order.referralNumber, - ReferralDate: store.order.referralDate, - ReferralCorrelationId: store.order.referralCorrelationId, - ReferralParentAccountNumber: store.order.accountNumber - }); +/* + Gets cookie value by name, returns empty string if not found. +*/ +function getCookieValueByName(name) { + const value = `; ${document.cookie}`; + const parts = value.split(`; ${name}=`); + + if (parts.length === 2) { + return parts.pop().split(';').shift(); + } + return ''; +} + +/* + Gets current domain without the subdomain for cookie. +*/ +function getDomainWithoutSubdomain() { + // eslint-disable-next-line no-restricted-globals + const url = location.hostname; + if (isLocalhost()) { + return 'localhost'; + } + + const urlParts = url.split('.'); + + return `.${urlParts + .slice(0) + .slice(-(urlParts.length === 4 ? 3 : 2)) + .join('.')}`; +} + +/* + Gets cookie domain value. Localhost will be empty "". +*/ +export function getCookieDomainValue() { + return isLocalhost() ? '' : `domain=${getDomainWithoutSubdomain()};`; +} + +/* + Used to create a cookie. + `useDefaultISSCookieAttributes` will set the path and domain to our defaults +*/ +function createOrUpdateCookie(key, value = '', + { useDefaultISSCookieAttributes = true, maxAge, isSecure = true }) { + let cookieToAdd = `${key}=${value}; `; + + if (useDefaultISSCookieAttributes) { + cookieToAdd += `path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()} `; + } + if (isSecure && !isLocalhost()) { + cookieToAdd += 'secure; '; + } + if (!Number.isNaN(maxAge)) { + cookieToAdd += `max-age=${maxAge};`; + } + + document.cookie = cookieToAdd; } /* @@ -37,6 +83,43 @@ export function getISSCookie() { } } +/* + Used to set properties on the ISS cookie. + Takes an object with properties to set. Will overwrite existing properties. +*/ +function setISSCookieProperties(properties) { + if (typeof properties === 'object') { + const cookie = getISSCookie(); + + if (cookie !== null) { + Object.keys(properties).forEach((key) => { + cookie[key] = properties[key]; + }); + } + + const cookieValueJson = JSON.stringify(cookie ?? {}); + createOrUpdateCookie(cookieNames.ISS_SESSION_INFO, cookieValueJson, {}); + } +} + +/* + Will update the cookie if present, or create a new one if not. +*/ +export function updateOrCreateISSCookie() { + const store = useMainStore(); + + // Set up cookie with all the props. + setISSCookieProperties({ + LastTouched: new Date().toUTCString(), + SavedSessionTimeoutDate: store.applicationUser.savedSessionTimeout, + ShouldResetState: false, + ReferralNumber: store.order.referralNumber, + ReferralDate: store.order.referralDate, + ReferralCorrelationId: store.order.referralCorrelationId, + ReferralParentAccountNumber: store.order.accountNumber + }); +} + /* Removes cookie from browser. */ @@ -44,13 +127,6 @@ export function deleteISSCookie() { createOrUpdateCookie(cookieNames.ISS_SESSION_INFO, undefined, { maxAge: 0 }); } -/* - Gets cookie domain value. Localhost will be empty "". -*/ -export function getCookieDomainValue() { - return isLocalhost() ? '' : `domain=${getDomainWithoutSubdomain()};`; -} - /* Gets value of dxdev cookie, and then extracts "did" value from it. Returns empty string if cookie not found or "did" string not present. @@ -118,83 +194,3 @@ export function setCookieProperties(properties, }); } } - -/* -=========================== -= PRIVATE FUNCTIONS = -=========================== -*/ - -/* - Used to set properties on the ISS cookie. - Takes an object with properties to set. Will overwrite existing properties. -*/ -function setISSCookieProperties(properties) { - if (typeof properties === 'object') { - const cookie = getISSCookie(); - - if (cookie !== null) { - Object.keys(properties).forEach((key) => { - cookie[key] = properties[key]; - }); - } - - const cookieValueJson = JSON.stringify(cookie ?? {}); - createOrUpdateCookie(cookieNames.ISS_SESSION_INFO, cookieValueJson, {}); - } -} - -/* - Used to create a cookie. - `useDefaultISSCookieAttributes` will set the path and domain to our defaults -*/ -function createOrUpdateCookie(key, value = '', - { useDefaultISSCookieAttributes = true, maxAge, isSecure = true }) { - let cookieToAdd = `${key}=${value}; `; - - if (useDefaultISSCookieAttributes) { - cookieToAdd += `path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()} `; - } - if (isSecure && !isLocalhost()) { - cookieToAdd += 'secure; '; - } - if (!Number.isNaN(maxAge)) { - cookieToAdd += `max-age=${maxAge};`; - } - - document.cookie = cookieToAdd; -} - -/* - Gets current domain without the subdomain for cookie. -*/ -function getDomainWithoutSubdomain() { - const url = location.hostname; - if (isLocalhost()) { - return 'localhost'; - } - - const urlParts = url.split('.'); - - return `.${urlParts - .slice(0) - .slice(-(urlParts.length === 4 ? 3 : 2)) - .join('.')}`; -} - -/* - Gets cookie value by name, returns empty string if not found. -*/ -function getCookieValueByName(name) { - const value = `; ${document.cookie}`; - const parts = value.split(`; ${name}=`); - - if (parts.length === 2) { - return parts.pop().split(';').shift(); - } - return ''; -} - -function isLocalhost() { - return location.hostname.includes('localhost'); -} diff --git a/src/helpers/damage-helper.js b/src/helpers/damage-helper.js index 3c6bfce2..7390167f 100644 --- a/src/helpers/damage-helper.js +++ b/src/helpers/damage-helper.js @@ -44,6 +44,7 @@ function hasMatchingReplacementOption(vehicleDamageOptions, selectedGlassToRepla Rear: 'backGlassOptions' }; + // eslint-disable-next-line no-restricted-syntax for (const glassToReplace of selectedGlassToReplace) { const propName = optionsMap[glassToReplace.glassLocation]; const { availableReplacementOptions } = vehicleDamageOptions[propName]; diff --git a/src/helpers/data-generation.js b/src/helpers/data-generation.js index c2d2323a..b156ca5d 100644 --- a/src/helpers/data-generation.js +++ b/src/helpers/data-generation.js @@ -1,9 +1,9 @@ import { randomUUID } from 'crypto'; export function getRandomInt(min = 0, max = 1000) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive + const minCeiling = Math.ceil(min); + const maxFloor = Math.floor(max); + return Math.floor(Math.random() * (maxFloor - minCeiling) + minCeiling); // The maximum is exclusive and the minimum is inclusive } export function getRandomGuid() { diff --git a/src/helpers/event-bus/event-bus.spec.js b/src/helpers/event-bus/event-bus.spec.js index e6aa9557..16501c4f 100644 --- a/src/helpers/event-bus/event-bus.spec.js +++ b/src/helpers/event-bus/event-bus.spec.js @@ -25,6 +25,7 @@ describe('event-bus.js', () => { it('removes items when readandpop is called', () => { useMainStore().eventBusItem.mockReturnValueOnce(event); + // TODO: Use or remove const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND); @@ -35,6 +36,7 @@ describe('event-bus.js', () => { it("doesn't try to remove items when readandpop is called and item doesn't exist", () => { useMainStore().eventBusItem.mockReturnValueOnce(undefined); + // TODO: Use or remove const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND); diff --git a/src/helpers/global-rule-definer.js b/src/helpers/global-rule-definer.js index 650fb97e..b06fe946 100644 --- a/src/helpers/global-rule-definer.js +++ b/src/helpers/global-rule-definer.js @@ -9,14 +9,10 @@ import { required, regex } from '@/helpers/validation-rules'; function defineGlobalNameRules() { defineRule(globalRules.FIRST_NAME_REQUIRED, required(errorMessages.FIRST_NAME_REQUIRED)); defineRule(globalRules.LAST_NAME_REQUIRED, required(errorMessages.LAST_NAME_REQUIRED)); - defineRule( - globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED, - required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED) - ); - defineRule( - globalRules.POLICYHOLDER_LAST_NAME_REQUIRED, - required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED) - ); + defineRule(globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED, + required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED)); + defineRule(globalRules.POLICYHOLDER_LAST_NAME_REQUIRED, + required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED)); } /** @@ -24,13 +20,9 @@ function defineGlobalNameRules() { */ function defineGlobalEmailRules() { defineRule(globalRules.EMAIL_ADDRESS_REQUIRED, required(errorMessages.EMAIL_ADDRESS_REQUIRED)); - defineRule( - globalRules.EMAIL_ADDRESS_FORMAT, - regex( - /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, - errorMessages.EMAIL_ADDRESS_FORMAT - ) - ); + defineRule(globalRules.EMAIL_ADDRESS_FORMAT, + regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, + errorMessages.EMAIL_ADDRESS_FORMAT)); } /** @@ -38,13 +30,9 @@ function defineGlobalEmailRules() { */ function defineGlobalPhoneNumberRules() { defineRule(globalRules.PHONE_NUMBER_REQUIRED, required(errorMessages.PHONE_NUMBER_REQUIRED)); - defineRule( - globalRules.PHONE_NUMBER_FORMAT, - regex( - /^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/, - errorMessages.PHONE_NUMBER_FORMAT - ) - ); + defineRule(globalRules.PHONE_NUMBER_FORMAT, + regex(/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/, + errorMessages.PHONE_NUMBER_FORMAT)); } /** diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 23e7781c..76029faa 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -1,7 +1,8 @@ -import { navigationScenarios } from '@/router/router-constants/navigation-scenarios.js'; import { RouterLinkStub } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { navigationScenarios } from '@/router/router-constants/navigation-scenarios.js'; import vehicleCategories from '@/constants/vehicle-categories.js'; -import { issPageValues } from '@/router/router-constants/issPage-values'; +import issPageValues from '@/router/router-constants/issPage-values'; import cookieNames from '@/constants/cookie-names'; import { Form } from 'vee-validate'; import baseMixin from '@/mixins/base-mixin'; @@ -13,7 +14,6 @@ import { GaActions } from '@/constants/analytics'; import queryStrings from '@/constants/query-strings'; import { useMainStore } from '@/store'; import { mapStores } from 'pinia'; -import { createTestingPinia } from '@pinia/testing'; const pinia = createTestingPinia(); useMainStore(pinia); @@ -147,10 +147,6 @@ export function getMountOptions(mockData) { return { global }; } - - - - export function getMockOrderInfo( mockReferralNumber, mockCorrelationId, @@ -169,7 +165,4 @@ export function getMockOrderInfo( }; } - - - -*/ \ No newline at end of file +*/ diff --git a/src/iss-components/site-footer/site-footer.vue b/src/iss-components/site-footer/site-footer.vue index eac378ab..f83d8372 100644 --- a/src/iss-components/site-footer/site-footer.vue +++ b/src/iss-components/site-footer/site-footer.vue @@ -49,7 +49,7 @@ diff --git a/src/router/router-constants/issPage-values.js b/src/router/router-constants/issPage-values.js index 9ddfab8c..4c98b188 100644 --- a/src/router/router-constants/issPage-values.js +++ b/src/router/router-constants/issPage-values.js @@ -8,6 +8,7 @@ const issPageValues = Object.freeze({ BAILOUT_PAGE: 'bailout-page', CAPABILITY_QUESTIONS: 'capability-questions', CONTACT_DETAILS: 'contact-details', + ENDORSEMENTS_PAGE: 'endorsements-page', ESTIMATE: 'estimate', COVERAGE_STATEMENT: 'coverage-statement', LICENSE_PLATE_LOOKUP: 'license-plate-lookup', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index a4093eaf..b61db6d8 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -603,7 +603,21 @@ const routingTable = () => [ destinationIssPageValue: issPageValues.BAILOUT_CONFIRMATION } ] - } + }, + { + issPageValue: issPageValues.ENDORSEMENTS_PAGE, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationIssPageValue: issPageValues.POLICY_VEHICLES + }, + { + scenario: navigationScenarios.CLICKED_FORWARD, + destinationIssPageValue: issPageValues.VEHICLE_DAMAGE + } + ] + }, + ]; export { routingTable }; From b523e2c976beda9be6daaf2c259776d69fbc4464 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Thu, 24 Aug 2023 11:57:00 -0400 Subject: [PATCH 053/674] add subheader to page --- src/layouts/endorsements-page/endorsements-page.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index 1e2513b4..dc92f80a 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -7,6 +7,7 @@
+
// Components import siteHeader from '@/iss-components/site-header/site-header.vue'; +import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue'; // Supporting files import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; @@ -33,6 +35,7 @@ export default { name: 'endorsements-page', components: { siteHeader, + siteSubHeader, siteFooter, // eslint-disable-next-line vue/no-reserved-component-names Form From 606b43ef8e316baa855cff0eb94e8221a317d60d Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Thu, 24 Aug 2023 11:57:23 -0400 Subject: [PATCH 054/674] navigation from policy-vehicles to endorsements --- src/layouts/policy-vehicles/policy-vehicles.vue | 10 ++++++++++ src/router/router-constants/navigation-scenarios.js | 1 + src/router/router-constants/routing-table.js | 7 ++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/layouts/policy-vehicles/policy-vehicles.vue b/src/layouts/policy-vehicles/policy-vehicles.vue index e10df300..dcd70af7 100644 --- a/src/layouts/policy-vehicles/policy-vehicles.vue +++ b/src/layouts/policy-vehicles/policy-vehicles.vue @@ -118,6 +118,10 @@ export default { ? vehicle?.coverages[0].deductible : 0; }, + endorsementsForSelectedVehicle() { + // hardcoded until endorsements service is ready + return true; + }, repairWaivedForSelectedVehicle() { const vehicle = this.policyVehicles.find((policyVehicle) => policyVehicle.vin === this.selectedVehicleVin); @@ -148,6 +152,7 @@ export default { // save selected vehicle to the store this.mainStore.updateVehicle(vehicle.data); this.displayGeneric = false; + console.log(this.endorsementsForSelectedVehicle); } } } @@ -194,6 +199,11 @@ export default { this.$route, {}, {}); + } else if (!!this.endorsementsForSelectedVehicle) { + this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS, + this.$route, + {}, + {}); } else { this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE, this.$route, diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 934065c1..2d2d4be3 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -24,6 +24,7 @@ const navigationScenarios = { // Policy Vehicle CLICKED_FORWARD_LISTED_VEHICLE: 'CLICKED_FORWARD_LISTED_VEHICLE', CLICKED_FORWARD_NON_LISTED_VEHICLE: 'CLICKED_FORWARD_NON_LISTED_VEHICLE', + CLICKED_FORWARD_WITH_ENDORSEMENTS: 'CLICKED_FORWARD_WITH_ENDORSEMENTS', // Vehicle Damage CLICKED_FORWARD_WITH_REPAIR: 'CLICKED_FORWARD_WITH_REPAIR', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index b61db6d8..a0622319 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -392,7 +392,12 @@ const routingTable = () => [ { scenario: navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT, destinationIssPageValue: issPageValues.BAILOUT_PAGE - } + }, + { + scenario: navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS, + destinationIssPageValue: issPageValues.ENDORSEMENTS_PAGE + }, + ] }, { From ccda6519419b584e88593b8ad144ad818d73bf0c Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Thu, 24 Aug 2023 14:37:23 -0400 Subject: [PATCH 055/674] endorsements WIP --- .../endorsements-page/endorsements-page.vue | 67 ++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index dc92f80a..720b86f9 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -7,7 +7,25 @@
- + + + + +
+ + From 25fa11629b3e66789d958f4dda4ddd4818af945a Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Thu, 24 Aug 2023 14:50:22 -0400 Subject: [PATCH 056/674] commit --- src/layouts/endorsements-page/endorsements-page.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index 720b86f9..46dac883 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -8,6 +8,7 @@
+
-
Date: Mon, 28 Aug 2023 08:59:37 -0400 Subject: [PATCH 057/674] Final eslint baseline PR linting 9 ! --- .eslintrc.js | 4 +- src/constants/error-messages.js | 1 + .../base-input-button/base-input-button.vue | 6 +- .../button-question/button-question.spec.js | 252 ++++++++---- .../textarea-question/textarea-question.vue | 11 +- .../textbox-question/textbox-question.vue | 5 +- src/global-methods.js | 66 +-- src/global-methods.spec.js | 91 +++-- src/helpers/clientauth-helper.js | 9 +- src/helpers/cookie-helper.js | 13 +- src/helpers/event-bus/event-bus.spec.js | 24 +- src/helpers/global-rule-definer.js | 32 +- src/helpers/layout-helper.js | 6 +- src/helpers/layout-helper.spec.js | 2 +- src/helpers/service-location-helper.js | 12 +- src/helpers/unit-test-helper.js | 5 +- .../address-questions.spec.js | 6 +- .../address-questions/address-questions.vue | 22 +- .../loading-modal/loading-modal.vue | 6 +- .../site-header/site-header.vue | 6 +- .../site-sub-header/site-sub-header.vue | 6 +- .../address-lookup/address-lookup.spec.js | 27 +- src/layouts/address-lookup/address-lookup.vue | 66 +-- .../address-vehicles-question.vue | 13 +- .../address-vehicles/address-vehicles.spec.js | 15 +- .../address-vehicles/address-vehicles.vue | 32 +- .../bailout-confirmation.vue | 2 +- src/layouts/bailout-page/bailout-page.vue | 8 +- .../capability-questions.vue | 14 +- .../contact-details/contact-details.vue | 6 +- .../coverage-statement.spec.js | 6 +- .../coverage-statement/coverage-statement.vue | 44 +- src/layouts/entry-page/entry-page.spec.js | 12 +- src/layouts/entry-page/entry-page.vue | 6 +- .../license-plate-lookup.spec.js | 33 +- .../license-plate-lookup.vue | 46 ++- .../molding-questions/molding-questions.vue | 26 +- .../order-confirmation/order-confirmation.vue | 8 +- .../part-questions/part-questions.spec.js | 3 + src/layouts/part-questions/part-questions.vue | 8 +- src/layouts/payment-page/payment-page.vue | 2 +- .../policy-holder-details.spec.js | 18 +- .../policy-holder-details.vue | 14 +- .../policy-vehicles/policy-vehicles.spec.js | 37 +- .../policy-vehicles/policy-vehicles.vue | 18 +- .../provider-pref-radio.spec.js | 6 +- .../provider-preference.spec.js | 12 +- .../provider-preference.vue | 2 +- .../shop-preference-modal.spec.js | 12 +- .../steering-modal/steering-modal.spec.js | 12 +- .../tpa-recal-modal/tpa-recal-modal.spec.js | 12 +- src/layouts/review-page/review-page.vue | 8 +- src/layouts/schedule-page/schedule-page.vue | 2 +- .../service-location/service-location.spec.js | 12 +- .../service-location/service-location.vue | 8 +- .../service-zip-modal-question.spec.js | 6 +- .../service-package-radio.spec.js | 6 +- .../service-packages/service-packages.vue | 2 +- .../tpa-confirmation/tpa-confirmation.vue | 8 +- src/layouts/tpa-search/tpa-search.vue | 8 +- src/layouts/tpa-submit/tpa-submit.vue | 8 +- .../damage-location-question.spec.js | 6 +- .../replace-options-question.spec.js | 15 +- .../side-door-options.spec.js | 6 +- .../side-door-options/side-door-options.vue | 24 +- src/layouts/vehicle-damage/vehicle-damage.vue | 32 +- .../windshield-options/windshield-options.vue | 42 +- src/layouts/vehicle-lookup/vehicle-lookup.vue | 2 +- .../vin-lookup-methods/vin-lookup-methods.vue | 2 +- .../glass-part-question.spec.js | 6 +- .../glass-part-question.vue | 6 +- .../vehicle-parts/vehicle-parts.spec.js | 72 ++-- src/layouts/vehicle-parts/vehicle-parts.vue | 2 +- .../vehicle-selection/vehicle-selection.vue | 8 +- src/layouts/vin-lookup/vin-lookup.spec.js | 42 +- src/layouts/vin-lookup/vin-lookup.vue | 14 +- src/layouts/welcome-page/welcome-page.spec.js | 24 +- src/layouts/welcome-page/welcome-page.vue | 26 +- src/mixins/analytics-mixin.js | 15 +- src/mixins/analytics-mixin.spec.js | 12 +- src/mixins/vehicle-questions-mixin.js | 37 +- src/mixins/vehicle-questions-mixin.spec.js | 383 ++++++++++-------- src/router/index.js | 30 +- src/store/store.spec.js | 8 +- src/ux-components/alert/alert.spec.js | 30 +- .../button-main/button-main.spec.js | 24 +- .../modal-button-main.spec.js | 48 ++- .../modal-button-main/modal-button-main.vue | 6 +- src/ux-components/text-link/text-link.vue | 6 +- 89 files changed, 1275 insertions(+), 826 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index c9deb6a3..3d578a28 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,8 +18,8 @@ module.exports = { 'vue/attribute-hyphenation': ['warn', 'never'], 'vue/v-on-event-hyphenation': ['warn', 'never'], 'object-curly-newline': ['error', { consistent: true }], - 'function-paren-newline': ['error', 'never'], - 'operator-linebreak': ['error', 'before', { overrides: { '=': 'after' }}], + 'function-paren-newline': ['error', 'multiline'], + 'operator-linebreak': ['error', 'before', { overrides: { '=': 'after' } }], 'implicit-arrow-linebreak': ['off'], 'comma-dangle': ['error', 'never'], indent: ['error', 4, { SwitchCase: 1 }], diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index caad0dfb..b63d9cd0 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -27,6 +27,7 @@ const errorMessages = Object.freeze({ SERVICE_ZIP_FORMAT: 'Please enter a valid service ZIP', VIN_REQUIRED: 'Please enter your VIN', VIN_FORMAT: + // eslint-disable-next-line max-len 'Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q', OPTION_REQUIRED: 'Please select an option', VEHICLE_REQUIRED: 'Please select a vehicle', diff --git a/src/digital-components/base-input-button/base-input-button.vue b/src/digital-components/base-input-button/base-input-button.vue index fdcf4480..301bb52e 100644 --- a/src/digital-components/base-input-button/base-input-button.vue +++ b/src/digital-components/base-input-button/base-input-button.vue @@ -50,9 +50,11 @@ export default { }; const { handleChange, meta, errors } = - useField(toRef(props, 'groupName'), + useField( + toRef(props, 'groupName'), toRef(props, 'validationRules'), - fieldOptions); + fieldOptions + ); return { handleChange, diff --git a/src/digital-components/button-question/button-question.spec.js b/src/digital-components/button-question/button-question.spec.js index 7e5720d3..6424abc4 100644 --- a/src/digital-components/button-question/button-question.spec.js +++ b/src/digital-components/button-question/button-question.spec.js @@ -62,8 +62,10 @@ describe('buttonQuestion.vue', () => { describe('selectedValues', () => { test('is radio => should emit captured value', async () => { // Arrange - const wrapper = shallowMount(buttonQuestion, - setupMocks({ propsData: { groupName: 'group-name' } })); + const wrapper = shallowMount( + buttonQuestion, + setupMocks({ propsData: { groupName: 'group-name' } }) + ); await wrapper.setProps({ answers: ['2022', '2021', '2020'], isMultiSelect: false, @@ -78,8 +80,10 @@ describe('buttonQuestion.vue', () => { }); test('is checkbox => should emit captured value', async () => { - const wrapper = shallowMount(buttonQuestion, - setupMocks({ propsData: { groupName: 'group-name' } })); + const wrapper = shallowMount( + buttonQuestion, + setupMocks({ propsData: { groupName: 'group-name' } }) + ); await wrapper.setProps({ answers: ['2022', '2021', '2020'], isMultiSelect: false, @@ -104,7 +108,8 @@ describe('buttonQuestion.vue', () => { describe('buttonLabel', () => { test('answers have buttonLabel properties => buttonsInfo buttonsLabel properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -116,7 +121,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -128,7 +134,8 @@ describe('buttonQuestion.vue', () => { test('answers have Text properties, no buttonLabel properties => buttonsInfo buttonsLabel properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -140,7 +147,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -152,7 +160,8 @@ describe('buttonQuestion.vue', () => { test('answers have buttonLabel and Text properties => buttonsInfo buttonsLabel properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -166,7 +175,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -178,12 +188,14 @@ describe('buttonQuestion.vue', () => { test('answers is an array of strings => buttonLabel is answer values', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: ['answer 1', 'answer 2'] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -197,7 +209,8 @@ describe('buttonQuestion.vue', () => { describe('altText', () => { test('answers have altText properties => buttonsInfo altText properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -209,7 +222,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -221,7 +235,8 @@ describe('buttonQuestion.vue', () => { test('answers have Name properties, no buttonLabel properties => buttonsInfo altText properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -233,7 +248,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -245,7 +261,8 @@ describe('buttonQuestion.vue', () => { test('answers have altText and Name properties => buttonsInfo altText properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -259,7 +276,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -271,12 +289,14 @@ describe('buttonQuestion.vue', () => { test('answers is an array of strings => altText is answer values', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: ['answer 1', 'answer 2'] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -290,7 +310,8 @@ describe('buttonQuestion.vue', () => { describe('buttonLabelSubCopy', () => { test('answers have buttonLabelSubCopy properties => buttonsInfo buttonLabelSubCopy properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -302,7 +323,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -314,7 +336,8 @@ describe('buttonQuestion.vue', () => { test('answers have SubText properties, no buttonLabelSubCopy properties => buttonsInfo buttonLabelSubCopy properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -326,7 +349,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -338,7 +362,8 @@ describe('buttonQuestion.vue', () => { test('answers have buttonLabelSubCopy and SubText properties => buttonsInfo buttonLabelSubCopy properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -352,7 +377,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -364,12 +390,14 @@ describe('buttonQuestion.vue', () => { test('answers is an array of strings => there are no buttonLabelSubCopy properties', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: ['answer 1', 'answer 2'] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -383,7 +411,8 @@ describe('buttonQuestion.vue', () => { describe('buttonImage', () => { test('answers have buttonImage properties => buttonsInfo buttonImage properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -395,7 +424,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -407,7 +437,8 @@ describe('buttonQuestion.vue', () => { test('answers have AnswerImageUrl properties, no buttonImage properties => buttonsInfo buttonImage properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -419,7 +450,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -431,7 +463,8 @@ describe('buttonQuestion.vue', () => { test('answers have buttonImage and AnswerImageUrl properties => buttonsInfo buttonImage properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -445,7 +478,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -457,12 +491,14 @@ describe('buttonQuestion.vue', () => { test('answers is an array of strings => there are no buttonImage properties', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: ['answer 1', 'answer 2'] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -476,7 +512,8 @@ describe('buttonQuestion.vue', () => { describe('buttonImageId', () => { test('answers have buttonImageId properties => buttonsInfo buttonImageId properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -488,7 +525,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -500,7 +538,8 @@ describe('buttonQuestion.vue', () => { test('answers have ImageId properties, no buttonImageId properties => buttonsInfo buttonImage properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -512,7 +551,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -524,7 +564,8 @@ describe('buttonQuestion.vue', () => { test('answers have buttonImageId and ImageId properties => buttonsInfo buttonImageId properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: [ @@ -538,7 +579,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -550,12 +592,14 @@ describe('buttonQuestion.vue', () => { test('answers is an array of strings => there are no buttonImageId properties', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: ['answer 1', 'answer 2'] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -568,16 +612,19 @@ describe('buttonQuestion.vue', () => { describe('groupName', () => { const answers = [[['answer 1', 'answer 2']], [[{ value: 1 }, { value: 2 }]]]; - test.each(answers)('answers have groupName properties with spaces => buttonsInfo groupName properties are correct', + test.each(answers)( + 'answers have groupName properties with spaces => buttonsInfo groupName properties are correct', (answerGroup) => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: answerGroup, groupName: 'this is my group name' } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -585,18 +632,22 @@ describe('buttonQuestion.vue', () => { // Assert expect(buttonsInfo[0].groupName).toEqual('this-is-my-group-name'); expect(buttonsInfo[1].groupName).toEqual('this-is-my-group-name'); - }); + } + ); - test.each(answers)('answers have groupName properties with no spaces => buttonsInfo groupName properties are correct', + test.each(answers)( + 'answers have groupName properties with no spaces => buttonsInfo groupName properties are correct', (answerGroup) => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { answers: answerGroup, groupName: 'this-is-my-group-name' } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -604,14 +655,16 @@ describe('buttonQuestion.vue', () => { // Assert expect(buttonsInfo[0].groupName).toEqual('this-is-my-group-name'); expect(buttonsInfo[1].groupName).toEqual('this-is-my-group-name'); - }); + } + ); }); describe('value', () => { describe('useTextForValue is true', () => { test('answers have value properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: true, @@ -624,7 +677,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -636,7 +690,8 @@ describe('buttonQuestion.vue', () => { test('answers have Text properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: true, @@ -649,7 +704,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -661,7 +717,8 @@ describe('buttonQuestion.vue', () => { test('answers have Name properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: true, @@ -674,7 +731,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -686,7 +744,8 @@ describe('buttonQuestion.vue', () => { test('answers have value and Text properties, no Name properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: true, @@ -701,7 +760,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -713,7 +773,8 @@ describe('buttonQuestion.vue', () => { test('answers have value and Name properties, no Text properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: true, @@ -728,7 +789,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -740,7 +802,8 @@ describe('buttonQuestion.vue', () => { test('answers have Text and Name properties, no value properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: true, @@ -755,7 +818,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -767,7 +831,8 @@ describe('buttonQuestion.vue', () => { test('answers have value, Text, and Name properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: true, @@ -784,7 +849,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -796,13 +862,15 @@ describe('buttonQuestion.vue', () => { test('answers is an array of strings => buttonInfo value property values are values from array', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: true, answers: ['answer 1', 'answer 2'] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -816,7 +884,8 @@ describe('buttonQuestion.vue', () => { describe('useTextForValue is false', () => { test('answers have value properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: false, @@ -829,7 +898,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -841,7 +911,8 @@ describe('buttonQuestion.vue', () => { test('answers have Text properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: false, @@ -854,7 +925,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -866,7 +938,8 @@ describe('buttonQuestion.vue', () => { test('answers have Name properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: false, @@ -879,7 +952,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -891,7 +965,8 @@ describe('buttonQuestion.vue', () => { test('answers have value and Text properties, no Name properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: false, @@ -906,7 +981,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -918,7 +994,8 @@ describe('buttonQuestion.vue', () => { test('answers have value and Name properties, no Text properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: false, @@ -933,7 +1010,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -945,7 +1023,8 @@ describe('buttonQuestion.vue', () => { test('answers have Text and Name properties, no value properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: false, @@ -960,7 +1039,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -972,7 +1052,8 @@ describe('buttonQuestion.vue', () => { test('answers have value, Text, and Name properties => buttonsInfo value properties are correct', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: false, @@ -989,7 +1070,8 @@ describe('buttonQuestion.vue', () => { } ] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; @@ -1001,13 +1083,15 @@ describe('buttonQuestion.vue', () => { test('answers is an array of strings => buttonInfo value property values are values from array', () => { // Arrange - const wrapper = shallowMount(buttonQuestion, + const wrapper = shallowMount( + buttonQuestion, setupMocks({ propsData: { useTextForValue: false, answers: ['answer 1', 'answer 2'] } - })); + }) + ); // Act const { buttonsInfo } = wrapper.vm; diff --git a/src/digital-components/textarea-question/textarea-question.vue b/src/digital-components/textarea-question/textarea-question.vue index 70d995f9..902cd2ca 100644 --- a/src/digital-components/textarea-question/textarea-question.vue +++ b/src/digital-components/textarea-question/textarea-question.vue @@ -84,15 +84,8 @@ export default { initialValue }; - const { errorMessage, - handleChange, - handleBlur, - validate, - errors, - resetField } = - useField(props.inputId, - props.validationRules, - fieldOptions); + const { errorMessage, handleChange, handleBlur, validate, errors, resetField } = + useField(props.inputId, props.validationRules, fieldOptions); return { errorMessage, diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index a380f51c..b619460e 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -131,9 +131,8 @@ export default { }; // eslint-disable-next-line no-shadow - const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField(props.inputId, - props.validationRules, - fieldOptions); + const { errorMessage, handleBlur, handleChange, meta, validate, errors } = + useField(props.inputId, props.validationRules, fieldOptions); return { errorMessage, diff --git a/src/global-methods.js b/src/global-methods.js index 4d333918..c32a6c9d 100644 --- a/src/global-methods.js +++ b/src/global-methods.js @@ -7,44 +7,45 @@ import { GaCategories, GaActions, GaLabels } from '@/constants/analytics'; import headerKeys from '@/constants/header-keys'; export default { - callHttpClient({ method, endpoint, payload, logApiCall = true}) { + callHttpClient({ method, endpoint, payload, logApiCall = true }) { return new Promise((resolve, reject) => { const store = useMainStore(); const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; - const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: 'SelfService' }); + const payloadAndAnalyticsData = { ...payload, AppName: 'SelfService' }; const headers = { [headerKeys.EXPERIMENT]: JSON.stringify(store.experimentSettings) }; - axios({ - method: method, + axios({ + method, url: cfDistroUrl + endpoint, data: payloadAndAnalyticsData, crossDomain: true, responseType: 'json', - headers: headers, + headers }) - .then((response) => { - if (logApiCall) { - analyticsMixIn.methods.pushEventToGA( - GaCategories.API_RESPONSE, - GaActions.RESULT, - `${GaLabels.SUCCESS}_${endpoint}`, - true - ); - } - return resolve(response); - }, - error => { - console.error(error); + .then( + (response) => { + if (logApiCall) { + analyticsMixIn.methods.pushEventToGA( + GaCategories.API_RESPONSE, + GaActions.RESULT, + `${GaLabels.SUCCESS}_${endpoint}`, + true + ); + } + return resolve(response); + }, + (error) => { + window.console.error(error); - // implement if analytics service is down - if (endpoint.includes('analytics')) { - return resolve({data: ''}); - } + // implement if analytics service is down + if (endpoint.includes('analytics')) { + return resolve({ data: '' }); + } - return reject(error.response); - } + return reject(error.response); + } ); }); }, @@ -52,19 +53,18 @@ export default { // used for mocked services async mockCallHttpClient(method, endpoint) { return new Promise((resolve, reject) => { - axios({ - method: method, + axios({ + method, url: endpoint, crossDomain: true, responseType: {} }) - .then((response) => { - return resolve(response); - }, - error => { - console.error(error); - return reject(error.response); - } + .then( + (response) => resolve(response), + (error) => { + window.console.error(error); + return reject(error.response); + } ); }); } diff --git a/src/global-methods.spec.js b/src/global-methods.spec.js index f5622ce6..3f0d0493 100644 --- a/src/global-methods.spec.js +++ b/src/global-methods.spec.js @@ -7,10 +7,54 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js'; jest.mock('axios'); jest.mock('@/mixins/analytics-mixin'); +/** @ignore */ +function setupMocksForHttpClient({ + endpoint = null, + isError = false, + additionalData = null +}) { + // Clear node module + axios.mockClear(); + + getMountOptions(); + + // Success Response + const response = { + status: 200, + data: { + message: 'Success', + additionalData + } + }; + + // Error Response + const error = { + response: { + status: 500, + data: { + message: 'Error', + additionalData + } + } + }; + + // Error interceptor on Axios returns a different object, so we need to mimic that. + if (isError) { + axios.mockRejectedValue(error); + } else { + axios.mockResolvedValue(response); + } + + return { + endpoint, + logApiCall: true + }; +} + it('Global Methods - Call Http Client - Should Resolve Promise', () => { // Arrange const endpoint = 'https://mock.safelite.com'; - const httpArgs = setupMocksForHttpClient({ endpoint: endpoint }); + const httpArgs = setupMocksForHttpClient({ endpoint }); // Act globalMethods.callHttpClient(httpArgs).then((response) => { @@ -25,7 +69,7 @@ it('Global Methods - Call Http Client - Should Reject Promise', () => { // Arrange const endpoint = 'https://mock.safelite.com'; const httpArgs = setupMocksForHttpClient({ - endpoint: endpoint, + endpoint, isError: true }); analyticsMixIn.methods.pushEventToGA = jest.fn(); @@ -38,46 +82,3 @@ it('Global Methods - Call Http Client - Should Reject Promise', () => { expect(err.status).toEqual(500); }); }); - -function setupMocksForHttpClient({ - endpoint = null, - isError = false, - additionalData = null -}) { - // Clear node module - axios.mockClear(); - - const mountOptions = getMountOptions(); - - // Success Response - const response = { - status: 200, - data: { - message: 'Success', - additionalData: additionalData - } - }; - - // Error Response - const error = { - response: { - status: 500, - data: { - message: 'Error', - additionalData: additionalData - } - } - }; - - // Error interceptor on Axios returns a different object, so we need to mimic that. - if (isError) { - axios.mockRejectedValue(error); - } else { - axios.mockResolvedValue(response); - } - - return { - endpoint: endpoint, - logApiCall: true - }; -} diff --git a/src/helpers/clientauth-helper.js b/src/helpers/clientauth-helper.js index 3d1a7f58..2bfd53bb 100644 --- a/src/helpers/clientauth-helper.js +++ b/src/helpers/clientauth-helper.js @@ -4,11 +4,10 @@ const validateISSClientTag = (clientTag) => { const store = useMainStore(); return store.validateClientTag(clientTag) - .then((response) => - // Success - response, - // Error - () => null); + .then( + (response) => response, + () => null + ); }; export default validateISSClientTag; diff --git a/src/helpers/cookie-helper.js b/src/helpers/cookie-helper.js index 2b93484b..5b858cfa 100644 --- a/src/helpers/cookie-helper.js +++ b/src/helpers/cookie-helper.js @@ -55,8 +55,11 @@ export function getCookieDomainValue() { Used to create a cookie. `useDefaultISSCookieAttributes` will set the path and domain to our defaults */ -function createOrUpdateCookie(key, value = '', - { useDefaultISSCookieAttributes = true, maxAge, isSecure = true }) { +function createOrUpdateCookie( + key, + value = '', + { useDefaultISSCookieAttributes = true, maxAge, isSecure = true } +) { let cookieToAdd = `${key}=${value}; `; if (useDefaultISSCookieAttributes) { @@ -188,8 +191,10 @@ export function updateSessionIdCookie() { createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 }); } -export function setCookieProperties(properties, - { useDefaultISSCookieAttributes = true, maxAge, isSecure }) { +export function setCookieProperties( + properties, + { useDefaultISSCookieAttributes = true, maxAge, isSecure } +) { if (typeof properties === 'object') { Object.keys(properties).forEach((key) => { createOrUpdateCookie(key, properties[key], { diff --git a/src/helpers/event-bus/event-bus.spec.js b/src/helpers/event-bus/event-bus.spec.js index 16501c4f..dc1e36bd 100644 --- a/src/helpers/event-bus/event-bus.spec.js +++ b/src/helpers/event-bus/event-bus.spec.js @@ -26,8 +26,10 @@ describe('event-bus.js', () => { useMainStore().eventBusItem.mockReturnValueOnce(event); // TODO: Use or remove - const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND); + const eventValue = eventBus.readAndPopEventFromBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ); expect(useMainStore().eventBusItem).toBeCalledTimes(1); expect(useMainStore().removeEventFromBus).toBeCalledTimes(1); @@ -37,8 +39,10 @@ describe('event-bus.js', () => { useMainStore().eventBusItem.mockReturnValueOnce(undefined); // TODO: Use or remove - const eventValue = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND); + const eventValue = eventBus.readAndPopEventFromBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ); expect(useMainStore().eventBusItem).toBeCalledTimes(1); expect(useMainStore().removeEventFromBus).toBeCalledTimes(0); @@ -47,17 +51,21 @@ describe('event-bus.js', () => { it('returns event from bus', () => { useMainStore().eventBusItem.mockReturnValueOnce(event); - const eventValue = eventBus.readEventFromBus(globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND); + const eventValue = eventBus.readEventFromBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ); expect(eventValue).toBe(event); }); it('Reads event from bus, should have event value.', () => { // Arrange / Act - eventBus.addEventToBus(globalEvents.Categories.GLOBAL_ALERT, + eventBus.addEventToBus( + globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND, - event); + event + ); expect(useMainStore().addEventToBus).toHaveBeenCalled(); }); diff --git a/src/helpers/global-rule-definer.js b/src/helpers/global-rule-definer.js index b06fe946..650fb97e 100644 --- a/src/helpers/global-rule-definer.js +++ b/src/helpers/global-rule-definer.js @@ -9,10 +9,14 @@ import { required, regex } from '@/helpers/validation-rules'; function defineGlobalNameRules() { defineRule(globalRules.FIRST_NAME_REQUIRED, required(errorMessages.FIRST_NAME_REQUIRED)); defineRule(globalRules.LAST_NAME_REQUIRED, required(errorMessages.LAST_NAME_REQUIRED)); - defineRule(globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED, - required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED)); - defineRule(globalRules.POLICYHOLDER_LAST_NAME_REQUIRED, - required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED)); + defineRule( + globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED, + required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED) + ); + defineRule( + globalRules.POLICYHOLDER_LAST_NAME_REQUIRED, + required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED) + ); } /** @@ -20,9 +24,13 @@ function defineGlobalNameRules() { */ function defineGlobalEmailRules() { defineRule(globalRules.EMAIL_ADDRESS_REQUIRED, required(errorMessages.EMAIL_ADDRESS_REQUIRED)); - defineRule(globalRules.EMAIL_ADDRESS_FORMAT, - regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, - errorMessages.EMAIL_ADDRESS_FORMAT)); + defineRule( + globalRules.EMAIL_ADDRESS_FORMAT, + regex( + /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, + errorMessages.EMAIL_ADDRESS_FORMAT + ) + ); } /** @@ -30,9 +38,13 @@ function defineGlobalEmailRules() { */ function defineGlobalPhoneNumberRules() { defineRule(globalRules.PHONE_NUMBER_REQUIRED, required(errorMessages.PHONE_NUMBER_REQUIRED)); - defineRule(globalRules.PHONE_NUMBER_FORMAT, - regex(/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/, - errorMessages.PHONE_NUMBER_FORMAT)); + defineRule( + globalRules.PHONE_NUMBER_FORMAT, + regex( + /^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/, + errorMessages.PHONE_NUMBER_FORMAT + ) + ); } /** diff --git a/src/helpers/layout-helper.js b/src/helpers/layout-helper.js index d13bbc2b..a4585342 100644 --- a/src/helpers/layout-helper.js +++ b/src/helpers/layout-helper.js @@ -1,4 +1,4 @@ -export function settleAllPromises(promiseResultMap) { +const settleAllPromises = (promiseResultMap) => { // Pull our keys out of the promise 'table' const promiseNames = Object.entries(promiseResultMap); @@ -22,4 +22,6 @@ export function settleAllPromises(promiseResultMap) { return resultMap; }); -} +}; + +export default settleAllPromises; diff --git a/src/helpers/layout-helper.spec.js b/src/helpers/layout-helper.spec.js index c8107580..758639c6 100644 --- a/src/helpers/layout-helper.spec.js +++ b/src/helpers/layout-helper.spec.js @@ -1,4 +1,4 @@ -import { settleAllPromises } from '@/helpers/layout-helper'; +import settleAllPromises from '@/helpers/layout-helper'; it('layout-helper: Should settle all promises and return mapped promise results', () => { // Arrange diff --git a/src/helpers/service-location-helper.js b/src/helpers/service-location-helper.js index 362f3d22..242752d3 100644 --- a/src/helpers/service-location-helper.js +++ b/src/helpers/service-location-helper.js @@ -1,11 +1,13 @@ import { useMainStore } from '@/store'; export async function getServiceabilityDetails(serviceZipCode, lineItems) { - const serviceabilityDetails = await useMainStore().getServiceabilityDetails({ - serviceZipCode, - lineItems - }, - false); + const serviceabilityDetails = await useMainStore().getServiceabilityDetails( + { + serviceZipCode, + lineItems + }, + false + ); return Promise.resolve(serviceabilityDetails); } diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 2bcfc8af..9ccfd29b 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -1,3 +1,4 @@ +/* eslint-disable import/no-extraneous-dependencies */ import { RouterLinkStub } from '@vue/test-utils'; import { createTestingPinia } from '@pinia/testing'; import navigationScenarios from '@/router/router-constants/navigation-scenarios.js'; @@ -59,7 +60,9 @@ export function getMountOptions(mockData) { // Heritage integration common methods export const cookies = { - [cookieNames.ISS_SESSION_INFO]: '{"ReferralNumber":"1566818","ReferralDate":"2022-03-15T10:56:24.597","ReferralCorrelationId":"404d2b04-f86e-45c3-b373-127b6217b060","ShouldResetState":false}', + [cookieNames.ISS_SESSION_INFO]: + // eslint-disable-next-line max-len + '{"ReferralNumber":"1566818","ReferralDate":"2022-03-15T10:56:24.597","ReferralCorrelationId":"404d2b04-f86e-45c3-b373-127b6217b060","ShouldResetState":false}', UNIQUE_SESSION_ID: '33756020-b58e-4ec7-b8b8-3f1576719c40', anotherCookie: '{}', someOtherCookie: '{}', diff --git a/src/iss-components/address-questions/address-questions.spec.js b/src/iss-components/address-questions/address-questions.spec.js index 60f8d692..6d225c65 100644 --- a/src/iss-components/address-questions/address-questions.spec.js +++ b/src/iss-components/address-questions/address-questions.spec.js @@ -311,7 +311,8 @@ describe('address-questions.vue', () => { describe('alerts', () => { const places = [null, { address_components: null }, undefined, {}]; - test.each(places)('selected place/place properties is null => display verification alert', + test.each(places)( + 'selected place/place properties is null => display verification alert', async (place) => { // Arrange const { wrapper } = setupMocks({}); @@ -336,7 +337,8 @@ describe('address-questions.vue', () => { const noMatchAlert = wrapper.findComponent({ ref: 'alertNoMatchWarning' }); expect(noMatchAlert.exists()).toBe(false); - }); + } + ); test('user enters address that yields no autocomplete results => show noMatch alert', async () => { // Arrange diff --git a/src/iss-components/address-questions/address-questions.vue b/src/iss-components/address-questions/address-questions.vue index 6e90deac..7ff88886 100644 --- a/src/iss-components/address-questions/address-questions.vue +++ b/src/iss-components/address-questions/address-questions.vue @@ -208,9 +208,11 @@ export default { }); // Standard place_changed event handling - const autocompleteListener = window.google.maps.event.addListener(autocomplete, + const autocompleteListener = window.google.maps.event.addListener( + autocomplete, 'place_changed', - fillInAddress); + fillInAddress + ); addressField1.addEventListener('focus', () => { // Wrapping the addressField1 element in the Google Address Autocomplete object @@ -265,14 +267,16 @@ export default { const firstResult = item.textContent; const geocoder = new window.google.maps.Geocoder(); - geocoder.geocode({ - address: firstResult - }, - (results, status) => { - if (status === window.google.maps.GeocoderStatus.OK) { - fillInAddress(results[0]); + geocoder.geocode( + { + address: firstResult + }, + (results, status) => { + if (status === window.google.maps.GeocoderStatus.OK) { + fillInAddress(results[0]); + } } - }); + ); } else { // No addresses found for the input self.matchFound = false; diff --git a/src/iss-components/loading-modal/loading-modal.vue b/src/iss-components/loading-modal/loading-modal.vue index fb7c270a..02deed69 100644 --- a/src/iss-components/loading-modal/loading-modal.vue +++ b/src/iss-components/loading-modal/loading-modal.vue @@ -48,7 +48,8 @@ export default { // Display modal this.isModalVisible = true; // Force page reload on back button - window.addEventListener('pageshow', + window.addEventListener( + 'pageshow', (evt) => { if (evt.persisted) { setTimeout(() => { @@ -56,7 +57,8 @@ export default { }, 10); } }, - false); + false + ); }, hideModal() { this.isModalVisible = false; diff --git a/src/iss-components/site-header/site-header.vue b/src/iss-components/site-header/site-header.vue index 5cf77eca..1666582c 100644 --- a/src/iss-components/site-header/site-header.vue +++ b/src/iss-components/site-header/site-header.vue @@ -65,8 +65,10 @@ export default ({ this.$nextTick(this.setupHeader); // Check if alert event is on the bus - const alertEvent = eventBus.readAndPopEventFromBus(globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND); + const alertEvent = eventBus.readAndPopEventFromBus( + globalEvents.Categories.GLOBAL_ALERT, + globalEvents.SubCategories.PAGE_NOT_FOUND + ); // If alert event is on the bus, then display the alert if (alertEvent !== undefined) { this.displayGlobalAlert = true; diff --git a/src/iss-components/site-sub-header/site-sub-header.vue b/src/iss-components/site-sub-header/site-sub-header.vue index 7e607804..4cd0af1d 100644 --- a/src/iss-components/site-sub-header/site-sub-header.vue +++ b/src/iss-components/site-sub-header/site-sub-header.vue @@ -57,8 +57,10 @@ export default { return this.getCmsContent(this.cmsWidgetName, this.contentProperty ?? 'SubHeaderText'); }, subText() { - let subTextFromCms = this.getCmsContent(this.cmsWidgetName, - this.subContentProperty ?? 'SecondaryText'); + let subTextFromCms = this.getCmsContent( + this.cmsWidgetName, + this.subContentProperty ?? 'SecondaryText' + ); if (this.stripRteStyle) { subTextFromCms = stripRteStyle(subTextFromCms); diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js index a891af3e..ddc65015 100644 --- a/src/layouts/address-lookup/address-lookup.spec.js +++ b/src/layouts/address-lookup/address-lookup.spec.js @@ -2,7 +2,7 @@ import addressLookup from '@/layouts/address-lookup/address-lookup.vue'; // Supporting Files -import { settleAllPromises } from '@/helpers/layout-helper.js'; +import settleAllPromises from '@/helpers/layout-helper.js'; import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { useMainStore } from '@/store'; @@ -14,9 +14,7 @@ jest.mock('@/helpers/damage-helper', () => ({ })); // Mock our module for promises. -jest.mock('@/helpers/layout-helper.js', () => ({ - settleAllPromises: jest.fn() -})); +jest.mock('@/helpers/layout-helper.js', () => jest.fn()); /** @ignore */ function setupMocks({ @@ -47,7 +45,8 @@ function setupMocks({ } })); - const wrapper = shallowMount(addressLookup, + const wrapper = shallowMount( + addressLookup, getMountOptions({ route: route || undefined, router: { @@ -71,7 +70,8 @@ function setupMocks({ } } - })); + }) + ); const apiResponses = { vinLookupResponse: { @@ -348,11 +348,13 @@ describe('address-lookup.vue', () => { await wrapper.vm.forwardButtonAction(); // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES, undefined, {}, {}, - carsFound); + carsFound + ); }); // eslint-disable-next-line max-len @@ -393,11 +395,14 @@ describe('address-lookup.vue', () => { await wrapper.vm.navigateForward(carsFound); // Assert - expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, + expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( + navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, undefined, {}, - { displayVehicleChangeAlert: true }); - }); + { displayVehicleChangeAlert: true } + ); + } + ); test('single car was found and matches entered vehicle => navigateForwardWithSingleCarMatch', async () => { // Arrange diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index b7d9d73e..5f913011 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -87,7 +87,7 @@ import { Form } from 'vee-validate'; // Supporting files import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; -import { settleAllPromises } from '@/helpers/layout-helper'; +import settleAllPromises from '@/helpers/layout-helper'; import routerParams from '@/router/router-constants/router-params'; import { getDamageString, isGlassAvailableForCarId } from '@/helpers/damage-helper'; @@ -142,8 +142,10 @@ export default { }, computed: { AlertMatchedDifferentVehicleHeader() { - return this.getCmsContent('AlertMatchedDifferentVehicleWidget', - 'HeadlineText').replaceAll('{custom:damage}', getDamageString()); + return this.getCmsContent( + 'AlertMatchedDifferentVehicleWidget', + 'HeadlineText' + ).replaceAll('{custom:damage}', getDamageString()); }, AlertMatchedDifferentVehicleBody() { const vinYmmFound = @@ -158,8 +160,10 @@ export default { .replaceAll('{custom:vinYmmExpected}', vinYmmExpected); }, AlertMatchedTwoIdenticalYMMVehicleHeader() { - return this.getCmsContent('AlertMatchedTwoIdenticalYMMVehicleWidget', - 'HeadlineText').replaceAll('{custom:damage}', getDamageString()); + return this.getCmsContent( + 'AlertMatchedTwoIdenticalYMMVehicleWidget', + 'HeadlineText' + ).replaceAll('{custom:damage}', getDamageString()); }, AlertMatchedTwoIdenticalYMMVehicleBody() { const vinYmmsFound = @@ -208,10 +212,12 @@ export default { }, attachCustomEvents() { this.prependActionToMethod(this, this.forwardButtonAction, () => { - this.pushEventToGA(this.$route.query[this.queryStrings.ISS_PAGE], + this.pushEventToGA( + this.$route.query[this.queryStrings.ISS_PAGE], this.GaActions.SUBMITTED, this.GaLabels.ADDRESS_LOOKUP, - true); + true + ); }); }, @@ -292,22 +298,24 @@ export default { } // Save vehicle, customer, service and registration information - await useMainStore().saveRegistrationAddressLookup({ - isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle, - vehicleInfo: - Object.keys(vehicleInfoToCommit).length === 0 - ? null - : vehicleInfoToCommit, - registrationInfo: { - firstName: this.customerQuestions.firstName, - lastName: this.customerQuestions.lastName, - address: this.customerQuestions.addressQuestions.streetAddress, - city: this.customerQuestions.addressQuestions.city, - state: this.customerQuestions.addressQuestions.state, - zipCode: this.customerQuestions.addressQuestions.zipCode - } - }, - false); + await useMainStore().saveRegistrationAddressLookup( + { + isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle, + vehicleInfo: + Object.keys(vehicleInfoToCommit).length === 0 + ? null + : vehicleInfoToCommit, + registrationInfo: { + firstName: this.customerQuestions.firstName, + lastName: this.customerQuestions.lastName, + address: this.customerQuestions.addressQuestions.streetAddress, + city: this.customerQuestions.addressQuestions.city, + state: this.customerQuestions.addressQuestions.state, + zipCode: this.customerQuestions.addressQuestions.zipCode + } + }, + false + ); return this.navigateForward(carsFound); }, @@ -322,18 +330,22 @@ export default { this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle ) { - this.$router.navigate(this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, + this.$router.navigate( + this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS, this.$route, {}, - { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }); + { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true } + ); } else if (matchingCars.length === 1) { await this.navigateForwardWithSingleCarMatch(); } else { - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES, + this.$router.navigate( + this.navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES, this.$route, {}, {}, - carsFound); + carsFound + ); } }, resetWarningsAndErrors() { diff --git a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue index 17e429cc..ba04cf22 100644 --- a/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue +++ b/src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue @@ -58,8 +58,10 @@ export default { emits: ['update: modelValue'], computed: { differentVehicleAlertHeader() { - return this.getCmsContent('AlertMatchedDifferentVehicleWidget', 'HeadlineText').replaceAll('{custom:damage}', - getDamageString()); + return this.getCmsContent( + 'AlertMatchedDifferentVehicleWidget', + 'HeadlineText' + ).replaceAll('{custom:damage}', getDamageString()); }, differentVehicleAlertBody() { const vinYmmFound = @@ -73,11 +75,14 @@ export default { .replaceAll('{custom:vinYmmExpected}', vinYmmExpected); }, AlertMatchedTwoIdenticalYMMVehicleHeader() { - return this.getCmsContent('AlertMatchedTwoIdenticalYMMVehicleWidget', - 'HeadlineText').replaceAll('{custom:damage}', getDamageString()); + return this.getCmsContent( + 'AlertMatchedTwoIdenticalYMMVehicleWidget', + 'HeadlineText' + ).replaceAll('{custom:damage}', getDamageString()); }, AlertMatchedTwoIdenticalYMMVehicleBody() { const vinYmmsFound = + // eslint-disable-next-line max-len `${this.selectedVehicle?.vehicle.year} ${this.selectedVehicle?.vehicle.make} ${this.selectedVehicle?.vehicle.model} ${this.selectedVehicle?.vehicle.style}`; const vinYmmsExpected = `${this.vehicleSelected?.year} ${this.vehicleSelected?.make} ${this.vehicleSelected?.model} ${this.vehicleSelected?.style}`; diff --git a/src/layouts/address-vehicles/address-vehicles.spec.js b/src/layouts/address-vehicles/address-vehicles.spec.js index 862e6569..caab2ae3 100644 --- a/src/layouts/address-vehicles/address-vehicles.spec.js +++ b/src/layouts/address-vehicles/address-vehicles.spec.js @@ -1,5 +1,5 @@ import addressVehicles from '@/layouts/address-vehicles/address-vehicles.vue'; -import { settleAllPromises } from '@/helpers/layout-helper.js'; +import settleAllPromises from '@/helpers/layout-helper.js'; import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { useMainStore } from '@/store'; @@ -21,9 +21,7 @@ jest.mock('@/helpers/cms-content-helper', () => ({ })); // Mock our module for promises. -jest.mock('@/helpers/layout-helper.js', () => ({ - settleAllPromises: jest.fn() -})); +jest.mock('@/helpers/layout-helper.js', () => jest.fn()); function setupMocks({ route = null, @@ -209,7 +207,8 @@ describe('address-vehicles.vue', () => { // Assert expect(wrapper.vm.$router.navigate).toBeCalledTimes(1); - }); + } + ); test('carId is not different on navigateForward (car was found) => Should handle navigating forward with car match', async () => { // Arrange @@ -233,10 +232,12 @@ describe('address-vehicles.vue', () => { useMainStore().order.vehicle.carId = 'CR00000395'; // Act - addressVehicles.beforeRouteEnter.call(wrapper.vm, + addressVehicles.beforeRouteEnter.call( + wrapper.vm, { query: { issPage: 'address-vehicles' } }, undefined, - (c) => c(wrapper.vm)); + (c) => c(wrapper.vm) + ); const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid(); diff --git a/src/layouts/address-vehicles/address-vehicles.vue b/src/layouts/address-vehicles/address-vehicles.vue index a7c12388..63cb3572 100644 --- a/src/layouts/address-vehicles/address-vehicles.vue +++ b/src/layouts/address-vehicles/address-vehicles.vue @@ -65,7 +65,7 @@ + + diff --git a/src/router/index.js b/src/router/index.js index bcf2fd46..1b2e8ace 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,3 +1,4 @@ +/* eslint-disable no-use-before-define */ import { createWebHistory, createRouter } from 'vue-router'; import lazyLoadComponent from '@/router/dynamic-routing/component-loader'; import issPageValues from '@/router/router-constants/issPage-values'; @@ -6,11 +7,8 @@ import { useMainStore } from '@/store'; import eventBus from '@/helpers/event-bus/event-bus'; import { globalEvents, globalEventTypes } from '@/constants/events'; import baseMixin from '@/mixins/base-mixin'; -import { - getDeviceIdValue, - updateOrCreateISSCookie, - updateSessionIdCookie -} from '@/helpers/cookie-helper'; +import { isSavedSessionStillActive } from '@/helpers/session-helper'; +import { getDeviceIdValue, getISSCookie, updateOrCreateISSCookie, updateSessionIdCookie } from '@/helpers/cookie-helper'; import { experimentTriggers } from '@/constants/experiments'; import applicationConfig from '@/constants/application-config'; @@ -23,29 +21,52 @@ const routes = [ name: 'root', async beforeEnter(to, from, next) { try { - to.query.issPage = !to.query.issPage - ? issPageValues.WELCOME_PAGE - : to.query.issPage; + const issPageToUse = !to.query.issPage ? issPageValues.WELCOME_PAGE : to.query.issPage; + + if ((issPageToUse === issPageValues.ACCESS_DENIED + || (issPageToUse !== issPageValues.ENTRY_PAGE && !useMainStore().issConfig.accountNumber)) + && process.env.VUE_APP_CURRENT_ENVIRONMENT !== 'Localhost' + ) { + return await GoToAccessIsDenied(next); + } // Do not run these for the main entry page - as it is not part of the user flow. - if (to.query.issPage !== issPageValues.ENTRY_PAGE) { + if (issPageToUse !== issPageValues.ENTRY_PAGE) { if (analyticsMixin.methods.noSession()) { await analyticsMixin.methods.initSession(); } else { updateSessionIdCookie(); } - await runExperiments(to.query.issPage); + await runExperiments(issPageToUse); // fmg has this further down + } + + // If the saved session has timed out, clear the session, execute 404 logic. + if (getISSCookie() !== null && !isSavedSessionStillActive()) { + // await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE); + await GoToStartOn404(next); } // Process ISS cookie. updateOrCreateISSCookie(); - if (router.hasRoute(to.query.issPage)) { - return next({ name: to.query.issPage, query: to.query, params: to.params }); + if (router.hasRoute(issPageToUse)) { + // Since our route is already in scope, we can grab the component and call the arePagePrerequisitesValid function. + let component = router.getRoutes().filter((x) => x.name === issPageToUse)[0].components; + + // If the component hasn't been loaded fully, load it before we check prerequisites. + if (component.default.methods === undefined) { + component = await component.default(); + } + + if (!arePagePrerequisitesValid(component)) { + await GoToStartOn404(next); + } + + return next({ name: issPageToUse, query: to.query, params: to.params }); } - const routeData = await GetRouteInfoFromPageName(to.query.issPage); + const routeData = await GetRouteInfoFromPageName(issPageToUse); if (routeData[0].name.toLowerCase() === 'error') { throw new Error('Page not found!'); @@ -58,6 +79,19 @@ const routes = [ component: routeData[0].component }); + // Call the next components arePagePrerequisitesValid method before load. + // If it returns false, use the 404 logic. + const nextComponent = await router + .getRoutes() + .filter((x) => x.name === routeData[0].name)[0] + .components.default(); + + if (!arePagePrerequisitesValid(nextComponent)) { + const tempMsgCopy = 'Pre Requisites failed, need to handle. Default is Welcome Page.'; + const tempMsgHeadline = `${issPageToUse}: pre-req failed...`; + await GoToStartOn404(next, tempMsgCopy, tempMsgHeadline); + } + // Assign current query string parameters, as well as our issPage one. next({ name: routeData[0].name, @@ -66,7 +100,7 @@ const routes = [ }); } catch (error) { window.console.warn(error); - GoToStartOn404(next); + await GoToStartOn404(next); } return null; } @@ -76,15 +110,13 @@ const routes = [ const router = createRouter({ history: createWebHistory('/'), routes, - scrollBehavior(to, from, savedPosition) { + scrollBehavior() { // always scroll to top return { top: 0 }; } }); -router.afterEach((to, from) => { - /*eslint-disable-line*/ - +router.afterEach((to) => { const store = useMainStore(); // Update lastPageVisited in the store store.updateLastPageVisited(to.name); @@ -119,36 +151,33 @@ async function GetRouteInfoFromPageName(pageName) { } // Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example. -router.overrideNavigation = (scenario, +router.overrideNavigation = ( + scenario, currentRoute, next, isSavingNavigation, optionalQuery = {}, optionalParams = {}, - optionalPageData) => { - navigate(scenario, - currentRoute, - isSavingNavigation, - optionalQuery, - optionalParams, - optionalPageData); + optionalPageData = {} +) => { + navigate( + scenario, currentRoute, isSavingNavigation, optionalQuery, optionalParams, optionalPageData + ); next(); }; -router.navigate = (scenario, - currentRoute, - optionalQuery = {}, - optionalParams = {}, - optionalPageData = {}) => { - navigate(scenario, currentRoute, optionalQuery, optionalParams, optionalPageData); +router.navigate = ( + scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {} +) => { + navigate( + scenario, currentRoute, optionalQuery, optionalParams, optionalPageData + ); }; // Navigate to the next route, depending on the scenario. -function navigate(scenario, - currentRoute, - optionalQuery = {}, - optionalParams = {}, - optionalPageData = {}) { +function navigate( + scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {} +) { /*eslint-disable-line*/ if (!scenario) { window.console.error('No scenario provided. Please review the routing table.'); @@ -172,9 +201,7 @@ function navigate(scenario, // Update page data to the store for next page if provided. Otherwise, keep existing page data or set to empty object const existingPageDataForPage = useMainStore().pageData(matchingScenarioMap.destinationIssPageValue); baseMixin.methods.savePageDataToStore(matchingScenarioMap.destinationIssPageValue, - Object.keys(optionalPageData).length > 0 - ? optionalPageData - : existingPageDataForPage ?? {}); + Object.keys(optionalPageData).length > 0 ? optionalPageData : existingPageDataForPage ?? {}); // We're always pushing the same path, just changing query strings. // Make sure our optional query strings get combined with our issPage one. @@ -194,7 +221,7 @@ function navigate(scenario, function navigateToUrl(url, optionalQuery = {}) { // possibly show some loading screen in the future here. const externalUrl = new URL(url); - // eslint-disable-next-line no-restricted-syntax + // eslint-disable-next-line no-restricted-syntax, guard-for-in for (const queryKey in optionalQuery) { externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]); } @@ -207,9 +234,7 @@ function getNavigationMap(scenario, currentRoute) { const issPageValue = currentRoute.query.issPage; try { const matchedQueryValue = routingTable(useMainStore()) - .filter((item) => - item.issPageValue === issPageValue - && item.maps.filter((map) => map.scenario === scenario).length > 0); + .filter((item) => item.issPageValue === issPageValue && item.maps.filter((map) => map.scenario === scenario).length > 0); const maps = matchedQueryValue ? matchedQueryValue.map((m) => m.maps.filter((map) => map.scenario === scenario))[0] : undefined; @@ -220,7 +245,21 @@ function getNavigationMap(scenario, currentRoute) { } } -function GoToStartOn404(next) { +async function GoToAccessIsDenied(next) { + const errorPageName = issPageValues.ACCESS_DENIED; + router.addRoute({ + path: '/', + name: errorPageName, + component: lazyLoadComponent(errorPageName) + }); + + next({ + name: errorPageName, + query: { issPage: errorPageName } + }); +} + +async function GoToStartOn404(next, msgCopy = null, msgHeadline = null) { const errorPageName = issPageValues.WELCOME_PAGE; router.addRoute({ path: '/', @@ -229,14 +268,12 @@ function GoToStartOn404(next) { }); // Put item on the bus - eventBus.addEventToBus(globalEvents.Categories.GLOBAL_ALERT, - globalEvents.SubCategories.PAGE_NOT_FOUND, - { - isDismissible: true, - messageCopy: 'You can get a quote by starting on this page.', - messageHeadline: "We're sorry, something went wrong.", - type: globalEventTypes.Danger - }); + eventBus.addEventToBus(globalEvents.Categories.GLOBAL_ALERT, globalEvents.SubCategories.PAGE_NOT_FOUND, { + isDismissible: true, + messageCopy: msgCopy ?? 'You can get a quote by starting on this page.', + messageHeadline: msgHeadline ?? "We're sorry, something went wrong.", + type: globalEventTypes.Danger + }); next({ name: errorPageName, @@ -244,6 +281,11 @@ function GoToStartOn404(next) { }); } +// Checks arePagePrerequisitesValid on the component passed in. +function arePagePrerequisitesValid(component) { + return component.default.methods.arePagePrerequisitesValid === undefined || component.default.methods.arePagePrerequisitesValid(); +} + // Run SiteEntry and PageEntry triggers for experiments async function runExperiments(nextPage) { const store = useMainStore(); diff --git a/src/router/router-constants/issPage-values.js b/src/router/router-constants/issPage-values.js index 9ddfab8c..68ad4a08 100644 --- a/src/router/router-constants/issPage-values.js +++ b/src/router/router-constants/issPage-values.js @@ -1,4 +1,5 @@ const issPageValues = Object.freeze({ + ACCESS_DENIED: 'access-denied', ENTRY_PAGE: 'entry-page', WELCOME_PAGE: 'welcome-page', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 4af22d4f..7830bac3 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -319,6 +319,15 @@ const routingTable = () => [ } ] }, + { + issPageValue: issPageValues.ACCESS_DENIED, + maps: [ + { + scenario: navigationScenarios.CLICKED_BACK, + destinationIssPageValue: issPageValues.ACCESS_DENIED + } + ] + }, { issPageValue: issPageValues.ENTRY_PAGE, maps: [ diff --git a/vue.config.js b/vue.config.js index 5018024e..a13ba34c 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,14 +1,14 @@ +/* eslint-disable max-len */ process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io'; process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; -process.env.VUE_APP_GOOGLE_PLACES_API_KEY - = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0'; +process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0'; // GA & GTM // NOTE: Using the old ISS site GTM Cotnainer ID for now, will create a new one soon. -process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY - = "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-KKNWZ3');"; -process.env.VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC - = 'https://www.googletagmanager.com/ns.html?id=GTM-KKNWZ3>m_auth=amlAYNhxUxuskQo7jmjadg>m_preview=env-38>m_cookies_win=x'; +process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY = + "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-KKNWZ3');"; +process.env.VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC = + 'https://www.googletagmanager.com/ns.html?id=GTM-KKNWZ3>m_auth=amlAYNhxUxuskQo7jmjadg>m_preview=env-38>m_cookies_win=x'; module.exports = { publicPath: '/', From 406476d6a6ce43d2d50e05d7f70a148642f9c7c3 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 28 Aug 2023 12:32:42 -0400 Subject: [PATCH 061/674] linting update --- .eslintrc.js | 5 +++-- src/router/index.js | 22 ++++++++-------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index c9deb6a3..440245f9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,8 +18,8 @@ module.exports = { 'vue/attribute-hyphenation': ['warn', 'never'], 'vue/v-on-event-hyphenation': ['warn', 'never'], 'object-curly-newline': ['error', { consistent: true }], - 'function-paren-newline': ['error', 'never'], - 'operator-linebreak': ['error', 'before', { overrides: { '=': 'after' }}], + 'function-paren-newline': ['error', 'multiline'], + 'operator-linebreak': ['error', 'before', { overrides: { '=': 'after' } }], 'implicit-arrow-linebreak': ['off'], 'comma-dangle': ['error', 'never'], indent: ['error', 4, { SwitchCase: 1 }], @@ -33,6 +33,7 @@ module.exports = { 'jsdoc/check-tag-names': ['error', { definedTags: ['store', 'endpoint', 'category', 'subcategory', 'remarks'] }], + 'jsdoc/require-jsdoc': 0, 'vue/html-self-closing': ['error', { html: { void: 'any', diff --git a/src/router/index.js b/src/router/index.js index 1b2e8ace..2fa73c97 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -160,24 +160,16 @@ router.overrideNavigation = ( optionalParams = {}, optionalPageData = {} ) => { - navigate( - scenario, currentRoute, isSavingNavigation, optionalQuery, optionalParams, optionalPageData - ); + navigate(scenario, currentRoute, isSavingNavigation, optionalQuery, optionalParams, optionalPageData); next(); }; -router.navigate = ( - scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {} -) => { - navigate( - scenario, currentRoute, optionalQuery, optionalParams, optionalPageData - ); +router.navigate = (scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {}) => { + navigate(scenario, currentRoute, optionalQuery, optionalParams, optionalPageData); }; // Navigate to the next route, depending on the scenario. -function navigate( - scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {} -) { +function navigate(scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {}) { /*eslint-disable-line*/ if (!scenario) { window.console.error('No scenario provided. Please review the routing table.'); @@ -200,8 +192,10 @@ function navigate( } else if (matchingScenarioMap.destinationIssPageValue) { // Update page data to the store for next page if provided. Otherwise, keep existing page data or set to empty object const existingPageDataForPage = useMainStore().pageData(matchingScenarioMap.destinationIssPageValue); - baseMixin.methods.savePageDataToStore(matchingScenarioMap.destinationIssPageValue, - Object.keys(optionalPageData).length > 0 ? optionalPageData : existingPageDataForPage ?? {}); + baseMixin.methods.savePageDataToStore( + matchingScenarioMap.destinationIssPageValue, + Object.keys(optionalPageData).length > 0 ? optionalPageData : existingPageDataForPage ?? {} + ); // We're always pushing the same path, just changing query strings. // Make sure our optional query strings get combined with our issPage one. From 70ef75bbc85a36ce88c1e14253b13c9c230ee754 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 28 Aug 2023 13:43:59 -0400 Subject: [PATCH 062/674] this.mainStore not available in preReq, some linting --- src/layouts/vehicle-damage/vehicle-damage.vue | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index fc8401eb..63e1a02d 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -138,8 +138,10 @@ export default { next((vm) => { vm.setCmsContent(resultMap.cmsContent); vm.$refs.damageLocation.initializeComponent(resultMap.damageOptions); - vm.$refs.sideDoorOptions.initializeComponent(resultMap.damageOptions.driverSideOptions.availableReplacementOptions, - resultMap.damageOptions.passengerSideOptions.availableReplacementOptions); + vm.$refs.sideDoorOptions.initializeComponent( + resultMap.damageOptions.driverSideOptions.availableReplacementOptions, + resultMap.damageOptions.passengerSideOptions.availableReplacementOptions + ); vm.$refs.windshieldOptions.initializeComponent(resultMap.damageOptions.windshieldOptions.availableReplacementOptions); vm.$refs.backGlassOptions.initializeComponent(resultMap.damageOptions.backGlassOptions.availableReplacementOptions); }); @@ -228,7 +230,7 @@ export default { }, methods: { arePagePrerequisitesValid() { - if (this.mainStore.order.vehicle.carId) { + if (useMainStore().order.vehicle.carId) { return true; } return false; @@ -362,23 +364,22 @@ export default { }, async forwardButtonAction() { - await this.mainStore.saveVehicleDamage(this.isWindshieldRepair, + await this.mainStore.saveVehicleDamage( + this.isWindshieldRepair, this.selectedGlassToReplace(), - this.selectedWindshieldOptions.selectedWindshieldChipCount); + this.selectedWindshieldOptions.selectedWindshieldChipCount + ); return this.navigateForward(); }, navigateForward() { if (this.mainStore.damage.isRepair) { - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR, - this.$route); + this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR, this.$route); } else if (this.mainStore.order.vehicle.vin) { // If vin already exists, navigate directly to vin-lookup - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_VIN, - this.$route); + this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_VIN, this.$route); } else { - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN, - this.$route); + this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN, this.$route); } }, From 65ba44105d55f03f65d8d9316d09559a8db160a5 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Mon, 28 Aug 2023 13:53:53 -0400 Subject: [PATCH 063/674] Finalizing save session call --- src/store/index.js | 58 ++++++++++++++++++----------------------- src/store/store.spec.js | 2 +- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 5a545eb6..831bf1fe 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -712,50 +712,42 @@ export const useMainStore = defineStore({ savedSessionId: applicationUser.savedSessionId }, order: { - // done vehicle: { - carId: vehicle.carId, year: vehicle.year, make: vehicle.make, model: vehicle.model, style: vehicle.style, vin: vehicle.vin, - imageUrl: vehicle.imageUrl, - imageVifColor: vehicle.imageColor, - imageVifNumber: vehicle.imageVifNumber, - registration: { - firstName: vehicle.registration.firstName, - lastName: vehicle.registration.lastName, - streetAddress: vehicle.registration.address, - city: vehicle.registration.city, - state: vehicle.registration.state, - zipCode: vehicle.registration.zipCode, - licensePlateNumber: vehicle.registration.licensePlate - } + carId: vehicle.carId, + licensePlateNumber: vehicle.registration.licensePlate }, - // done damage: { numberOfChips: damage.numberOfChips, glassToReplace: newGlassToReplace, isRepair: damage.isRepair, partQuestionAnswers: order.damage.partQuestionAnswers, moldingQuestionAnswers: order.damage.moldingQuestionAnswers, - capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers - }, - policy: { - policyNumber: policy.policyNumber, - policyZipCode: policy.policyZipCode, + capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers, dateOfLoss: policy.dateOfLoss, damageCause: policy.damageCause, damageState: policy.damageState, damageCity: policy.damageCity, - isDamageGlassOnly: policy.isDamageGlassOnly, + isDamageGlassOnly: policy.isDamageGlassOnly + }, + policy: { + policyHolder: { + policyFirstName: order.customer.firstName, + policyLastName: order.customer.lastName, + policyPhoneNumber: order.customer.phoneNumber, + policyEmail: order.customer.emailAddress + }, + policyNumber: policy.policyNumber, + policyZipCode: policy.policyZipCode, noCoverage: policy.noCoverage, policyLookupSuccessful: policy.policyLookupSuccessful, originalDeductible: order.originalDeductible, currentDeductible: order.currentDeductible }, - // TODO incorporate name and email contact details where appropriate customer: { address: { streetAddress: order.customer.address.streetAddress, @@ -764,16 +756,14 @@ export const useMainStore = defineStore({ state: order.customer.address.state, zipCode: order.customer.address.zipCode }, - emailAddress: order.customer.emailAddress, - firstName: order.customer.firstName, - lastName: order.customer.lastName, - policyPhoneNumber: order.customer.phoneNumber, - smsPhoneNumber: order.contactInfo.requestTextUpdates ? order.contactInfo.phoneNumber : null, + emailAddress: order.contactInfo.emailAddress, + firstName: order.contactInfo.firstName, + lastName: order.contactInfo.lastName, + phoneNumber: order.contactInfo.phoneNumber, optInSms: order.contactInfo.requestTextUpdates ?? false }, lineItems: { glassParts: lineItems.glassParts, - otherData: lineItems.otherData, supportingItems: lineItems.supportingItems, vaps: lineItems.vaps }, @@ -786,11 +776,13 @@ export const useMainStore = defineStore({ parentAccountNumber: this.issConfig.accountNumber }, serviceLocation: { - streetAddress: order.serviceLocation.address, - city: order.serviceLocation.city, - state: order.serviceLocation.state, - zipCode: order.serviceLocation.zipCode, - zipCodeCtu: order.serviceLocation.zipCodeCtu, + address: { + streetAddress: order.serviceLocation.address, + city: order.serviceLocation.city, + state: order.serviceLocation.state, + zipCode: order.serviceLocation.zipCode, + zipCodeCtu: order.serviceLocation.zipCodeCtu + }, techNotes: order.contactInfo.notesForTechnician }, schedule: { diff --git a/src/store/store.spec.js b/src/store/store.spec.js index c8be5dbc..a4d02857 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -74,7 +74,7 @@ describe('Store', () => { expect(store.applicationUser.eventBus.length).toBe(1); // Act - store.removeEventFromBus({ category: event.category, subCategory: event.subCategory }) + store.removeEventFromBus({ category: event.category, subCategory: event.subCategory }); // Assert expect(store.applicationUser.eventBus.length).toBe(0); From 521485ad6e02b13ba1f49927956501161bebcd56 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Mon, 28 Aug 2023 14:03:09 -0400 Subject: [PATCH 064/674] Cleaning up store --- src/store/index.js | 86 ++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index f71aa9cd..ed1be634 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -17,7 +17,6 @@ const storeId = 'main'; const getDefaultState = () => ({ order: { - // Same as FMG vehicle: { year: null, make: null, @@ -39,7 +38,6 @@ const getDefaultState = () => ({ lastName: null } }, - // Same as FMG damage: { isRepair: null, numberOfChips: null, @@ -48,7 +46,6 @@ const getDefaultState = () => ({ moldingQuestionAnswers: null, capabilityQuestionAnswers: null }, - // DNE in FMG policy: { policyNumber: null, policyZipCode: null, @@ -64,8 +61,6 @@ const getDefaultState = () => ({ replace: null // numerical value; how much customer owes on deductible in replace case, } }, - // FMG only has email - // CSR-1358 and CSR-1359 customer: { address: { streetAddress: null, @@ -79,7 +74,6 @@ const getDefaultState = () => ({ emailAddress: null, phoneNumber: null }, - // Many more details in FMG serviceLocation: { address: null, city: null, @@ -696,17 +690,14 @@ export const useMainStore = defineStore({ }, saveSession() { - // TODO use pieces of actual store - const { vehicle, damage, policy, order, applicationUser, lineItems } = this.order; - - // TODO what does this method do + const { vehicle, damage, policy, customer, contactInfo, payment, applicationUser, + lineItems, serviceLocation, schedule } = this.order; const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); return globalMethods.callHttpClient({ method: endpoints.SaveSession.method, endpoint: endpoints.SaveSession.url, payload: { - // done applicationUser: { crmCustomerId: applicationUser.crmCustomerId, experiments: applicationUser.experiments, @@ -728,9 +719,9 @@ export const useMainStore = defineStore({ numberOfChips: damage.numberOfChips, glassToReplace: newGlassToReplace, isRepair: damage.isRepair, - partQuestionAnswers: order.damage.partQuestionAnswers, - moldingQuestionAnswers: order.damage.moldingQuestionAnswers, - capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers, + partQuestionAnswers: damage.partQuestionAnswers, + moldingQuestionAnswers: damage.moldingQuestionAnswers, + capabilityQuestionAnswers: damage.capabilityQuestionAnswers, dateOfLoss: policy.dateOfLoss, damageCause: policy.damageCause, damageState: policy.damageState, @@ -739,31 +730,31 @@ export const useMainStore = defineStore({ }, policy: { policyHolder: { - policyFirstName: order.customer.firstName, - policyLastName: order.customer.lastName, - policyPhoneNumber: order.customer.phoneNumber, - policyEmail: order.customer.emailAddress + policyFirstName: customer.firstName, + policyLastName: customer.lastName, + policyPhoneNumber: customer.phoneNumber, + policyEmail: customer.emailAddress }, policyNumber: policy.policyNumber, policyZipCode: policy.policyZipCode, noCoverage: policy.noCoverage, policyLookupSuccessful: policy.policyLookupSuccessful, - originalDeductible: order.originalDeductible, - currentDeductible: order.currentDeductible + originalDeductible: this.order.originalDeductible, + currentDeductible: this.order.currentDeductible }, customer: { address: { - streetAddress: order.customer.address.streetAddress, - streetAddress2: order.customer.address.streetAddress2, - city: order.customer.address.city, - state: order.customer.address.state, - zipCode: order.customer.address.zipCode + streetAddress: customer.address.streetAddress, + streetAddress2: customer.address.streetAddress2, + city: customer.address.city, + state: customer.address.state, + zipCode: customer.address.zipCode }, - emailAddress: order.contactInfo.emailAddress, - firstName: order.contactInfo.firstName, - lastName: order.contactInfo.lastName, - phoneNumber: order.contactInfo.phoneNumber, - optInSms: order.contactInfo.requestTextUpdates ?? false + emailAddress: contactInfo.emailAddress, + firstName: contactInfo.firstName, + lastName: contactInfo.lastName, + phoneNumber: contactInfo.phoneNumber, + optInSms: contactInfo.requestTextUpdates ?? false }, lineItems: { glassParts: lineItems.glassParts, @@ -772,36 +763,35 @@ export const useMainStore = defineStore({ }, payment: { InsuranceCoverage: { - isVerified: order.payment.insuranceCoverage.isVerified ?? false, - coverageStatus: order.payment.insuranceCoverage.coverageStatus + isVerified: payment.insuranceCoverage.isVerified ?? false, + coverageStatus: payment.insuranceCoverage.coverageStatus }, - isInsurance: order.payment.isInsurance ?? true, + isInsurance: payment.isInsurance ?? true, parentAccountNumber: this.issConfig.accountNumber }, serviceLocation: { address: { - streetAddress: order.serviceLocation.address, - city: order.serviceLocation.city, - state: order.serviceLocation.state, - zipCode: order.serviceLocation.zipCode, - zipCodeCtu: order.serviceLocation.zipCodeCtu + streetAddress: serviceLocation.address, + city: serviceLocation.city, + state: serviceLocation.state, + zipCode: serviceLocation.zipCode, + zipCodeCtu: serviceLocation.zipCodeCtu }, - techNotes: order.contactInfo.notesForTechnician + techNotes: contactInfo.notesForTechnician }, schedule: { - date: order.schedule?.date, - startTime: order.schedule?.startTime, - endTime: order.schedule?.endTime, - routeCode: order.schedule?.routeCode, - jobMaxMinutes: order.schedule?.jobMaxMinutes + date: schedule?.date, + startTime: schedule?.startTime, + endTime: schedule?.endTime, + routeCode: schedule?.routeCode, + jobMaxMinutes: schedule?.jobMaxMinutes }, - referralDate: order.referralDate, - referralNumber: order.referralNumber?.toString() + referralDate: this.order.referralDate, + referralNumber: this.order.referralNumber?.toString() } }, - // TODO maybe modify additionalSuccessEventDataHandler: (response) => - `Email provided: ${order.customer.emailAddress ? 'true' : 'false'}` + `Email provided: ${customer.emailAddress ? 'true' : 'false'}` }); }, From 260287e6a616d987449636789d02455fde87a1c3 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Mon, 28 Aug 2023 14:06:46 -0400 Subject: [PATCH 065/674] Call save session with every route --- src/router/index.js | 1 + src/store/index.js | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index bcf2fd46..44e5e5a8 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -88,6 +88,7 @@ router.afterEach((to, from) => { const store = useMainStore(); // Update lastPageVisited in the store store.updateLastPageVisited(to.name); + store.saveSession(); if (to.query.issPage !== issPageValues.ENTRY_PAGE) { // Push page view to GA diff --git a/src/store/index.js b/src/store/index.js index ed1be634..bc3d8566 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -81,10 +81,9 @@ const getDefaultState = () => ({ zipCode: null, zipCodeCtu: null }, - // otherParts vs serverData lineItems: { glassParts: null, - otherParts: null, // TODO what is this? + otherParts: null, supportingItems: null, vaps: null }, @@ -98,7 +97,6 @@ const getDefaultState = () => ({ }, referralNumber: null, referralDate: null, - // DNE in FMG contactInfo: { firstName: null, lastName: null, From 845604bd0fa2acb07041f0e42fe467a5218a7cf3 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Mon, 28 Aug 2023 14:08:18 -0400 Subject: [PATCH 066/674] Updating save session endpoint --- src/constants/endpoints.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 925fde7a..a213e2f4 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -131,7 +131,7 @@ const endpoints = Object.freeze({ method: 'POST' }, SaveSession: { - url: '/order/api/v1/order/save-session', + url: '/order/api/v1/order/save-session/iss', method: 'POST' } }); From e8a1f9f17951256917ddd7cb95923cc835beef65 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Mon, 28 Aug 2023 14:10:10 -0400 Subject: [PATCH 067/674] Reverting needless updated --- src/store/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index bc3d8566..4c8603e0 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,9 +2,9 @@ /* eslint-disable no-use-before-define */ /* eslint-disable max-len */ import { defineStore } from 'pinia'; -import { endpoints } from '@/constants/endpoints.js'; +import { endpoints } from '@/constants/endpoints'; // eslint-disable-next-line import/no-cycle -import { getDateForSavedSessionTimeout } from '@/helpers/session-helper.js'; +import { getDateForSavedSessionTimeout } from '@/helpers/session-helper'; // eslint-disable-next-line import/no-cycle import globalMethods from '@/global-methods'; import { experimentTriggers } from '@/constants/experiments'; @@ -87,7 +87,6 @@ const getDefaultState = () => ({ supportingItems: null, vaps: null }, - // Add parent account number from FMG payment: { isInsurance: true, // TODO delete; irrelevant to ISS insuranceCoverage: { From 712858dea2678982d2b5dae95f53d70c5e8eeeb3 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Mon, 28 Aug 2023 14:11:14 -0400 Subject: [PATCH 068/674] Remove unnecessary eslint ignore --- src/store/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 4c8603e0..e89cdb27 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,5 +1,3 @@ -/* eslint-disable no-shadow */ -/* eslint-disable no-use-before-define */ /* eslint-disable max-len */ import { defineStore } from 'pinia'; import { endpoints } from '@/constants/endpoints'; From 921b358a9a605faf75103cf1a7b4b1d26841720f Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 28 Aug 2023 16:07:24 -0400 Subject: [PATCH 069/674] button question functionality --- .../endorsements-page/endorsements-page.vue | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index 17410a15..4277b73b 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -9,25 +9,14 @@
-
- -
- + Date: Tue, 29 Aug 2023 13:46:12 -0400 Subject: [PATCH 070/674] save supporting items on windshield repair --- src/layouts/vehicle-damage/vehicle-damage.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index 595aef6f..cb8338a8 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -364,11 +364,17 @@ export default { }, async forwardButtonAction() { - await this.mainStore.saveVehicleDamage( + this.mainStore.saveVehicleDamage( this.isWindshieldRepair, this.selectedGlassToReplace(), this.selectedWindshieldOptions.selectedWindshieldChipCount ); + + if (this.isWindshieldRepair) { + const supportingItems = await useMainStore().getSupportingItems(); + useMainStore().saveSupportingItems(supportingItems.data); + } + return this.navigateForward(); }, From 6f63484dffcd4e279a6735948214cf0358859308 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 29 Aug 2023 15:57:23 -0400 Subject: [PATCH 071/674] updates to vehicle damage page. --- src/digital-components/base-input-button/base-input-button.vue | 3 ++- src/layouts/vehicle-damage/vehicle-damage.vue | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/digital-components/base-input-button/base-input-button.vue b/src/digital-components/base-input-button/base-input-button.vue index 301bb52e..f619a16e 100644 --- a/src/digital-components/base-input-button/base-input-button.vue +++ b/src/digital-components/base-input-button/base-input-button.vue @@ -74,7 +74,8 @@ export default { return this.modelValue.includes(this.value); } if (!this.isMultiSelect) { - return this.modelValue === this.value; + // eslint-disable-next-line eqeqeq + return this.modelValue == this.value; } return false; }, diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index cb8338a8..4a53e854 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -372,7 +372,7 @@ export default { if (this.isWindshieldRepair) { const supportingItems = await useMainStore().getSupportingItems(); - useMainStore().saveSupportingItems(supportingItems.data); + this.mainStore.saveSupportingItems(supportingItems.data); } return this.navigateForward(); From 8e5dddd7ccd6aa0d239631501b7d350e89984c17 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 30 Aug 2023 11:29:25 -0400 Subject: [PATCH 072/674] fix test --- .../vehicle-damage/vehicle-damage.spec.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/layouts/vehicle-damage/vehicle-damage.spec.js b/src/layouts/vehicle-damage/vehicle-damage.spec.js index 56a6c4dd..f2f911f7 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.spec.js +++ b/src/layouts/vehicle-damage/vehicle-damage.spec.js @@ -3,6 +3,7 @@ import { mount, flushPromises } from '@vue/test-utils'; import { createTestingPinia } from '@pinia/testing'; import navigationScenarios from '@/router/router-constants/navigation-scenarios'; import routerParams from '@/router/router-constants/router-params'; +import { useMainStore } from '@/store'; import vehicleCategories from '@/constants/vehicle-categories'; import VehicleDamageComponent from '@/layouts/vehicle-damage/vehicle-damage.vue'; @@ -69,6 +70,21 @@ describe('vehicle-damage.vue', () => { const wrapper = mount(VehicleDamageComponent, mountOptions); const siteFooterWrapper = wrapper.getComponent({ ref: 'siteFooter' }); + useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve({ + data: { data: [ + { + description: null, + partNumber: 'SUPPLIES-REPAIR', + partType: 'REPAIR FEE' + }, + { + description: null, + partNumber: 'WSREPAIR', + partType: 'REPAIR FEE' + } + ] } + })); + siteFooterWrapper.vm.$emit('forwardClicked'); await flushPromises(); From d7cc2a3ed99fbe21b8011e76b7e814656b2e1c7c Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 30 Aug 2023 13:16:14 -0400 Subject: [PATCH 073/674] bailout-confirmation renamed to contact-confirmation --- .../contact-confirmation.vue} | 0 src/router/router-constants/issPage-values.js | 2 +- src/router/router-constants/routing-table.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/layouts/{bailout-confirmation/bailout-confirmation.vue => contact-confirmation/contact-confirmation.vue} (100%) diff --git a/src/layouts/bailout-confirmation/bailout-confirmation.vue b/src/layouts/contact-confirmation/contact-confirmation.vue similarity index 100% rename from src/layouts/bailout-confirmation/bailout-confirmation.vue rename to src/layouts/contact-confirmation/contact-confirmation.vue diff --git a/src/router/router-constants/issPage-values.js b/src/router/router-constants/issPage-values.js index 68ad4a08..d79f748f 100644 --- a/src/router/router-constants/issPage-values.js +++ b/src/router/router-constants/issPage-values.js @@ -5,9 +5,9 @@ const issPageValues = Object.freeze({ ADDRESS_LOOKUP: 'address-lookup', ADDRESS_VEHICLES: 'address-vehicles', - BAILOUT_CONFIRMATION: 'bailout-confirmation', BAILOUT_PAGE: 'bailout-page', CAPABILITY_QUESTIONS: 'capability-questions', + CONTACT_CONFIRMATION: 'contact-confirmation', CONTACT_DETAILS: 'contact-details', ESTIMATE: 'estimate', COVERAGE_STATEMENT: 'coverage-statement', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 7830bac3..c3fbe633 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -609,7 +609,7 @@ const routingTable = () => [ }, { scenario: navigationScenarios.CLICKED_FORWARD, - destinationIssPageValue: issPageValues.BAILOUT_CONFIRMATION + destinationIssPageValue: issPageValues.CONTACT_CONFIRMATION } ] } From b8a53d94d9b93bb7830782b7428be6e046b0e4bc Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 29 Aug 2023 13:44:09 -0400 Subject: [PATCH 074/674] preReqs --- .../service-location/service-location.vue | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 939f5aa6..31a0a9fc 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -118,10 +118,7 @@ export default { next((vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.setData( - resultMap.zipCodeData, - resultMap.serviceabilityDetails - ); + vm.setData(resultMap.zipCodeData, resultMap.serviceabilityDetails); }); }, setup() { @@ -172,8 +169,15 @@ export default { } }, methods: { - arePagePrerequisiteValid() { - return true; + arePagePrerequisitesValid() { + console.log('hi'); + console.log(useMainStore().lineItems.supportingItems); + console.log(useMainStore().order.serviceLocation.zipCode); + + return ( + useMainStore().lineItems.supportingItems !== null + && useMainStore().order.serviceLocation.zipCode !== null + ); }, backButtonAction() { /** From 9fc06b097c631a1e4dfff820fdc436febba3521c Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 30 Aug 2023 13:57:32 -0400 Subject: [PATCH 075/674] update servicelocation zipcode in store to match customer zipcode --- src/layouts/welcome-page/welcome-page.vue | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 0607f008..e9943ba6 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -325,14 +325,16 @@ export default { const policy = policyInfo.policies?.[0]; if (policy) { // populate policy holder details from policy lookup - this.mainStore.order.customer.address.streetAddress = - policy.insureds?.[0]?.address; + this.mainStore.order.customer.address.streetAddress = policy.insureds?.[0]?.address; this.mainStore.order.customer.address.city = policy.insureds?.[0]?.city; this.mainStore.order.customer.address.state = policy.insureds?.[0]?.state; this.mainStore.order.customer.address.zipCode = policy.insureds?.[0]?.zipCode; this.mainStore.order.customer.firstName = policy.insureds?.[0]?.firstName; this.mainStore.order.customer.lastName = policy.insureds?.[0]?.lastName; + // populate additional fields + this.mainStore.order.serviceLocation.zipCode = policy.insureds?.[0]?.zipCode; + // populate vehicles this.vehiclesFound = policy.vehicles; } From d3882a8d96caecb5f679f270d9d79dce560fda53 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 30 Aug 2023 13:59:09 -0400 Subject: [PATCH 076/674] remove console logs --- src/layouts/service-location/service-location.vue | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 31a0a9fc..252741c1 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -170,10 +170,6 @@ export default { }, methods: { arePagePrerequisitesValid() { - console.log('hi'); - console.log(useMainStore().lineItems.supportingItems); - console.log(useMainStore().order.serviceLocation.zipCode); - return ( useMainStore().lineItems.supportingItems !== null && useMainStore().order.serviceLocation.zipCode !== null From 8a93a379499b13f2bdc65f0337d1a13b6f6b3743 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 30 Aug 2023 15:57:46 -0400 Subject: [PATCH 077/674] add servicelocation zipcode to --- src/store/index.js | 146 ++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 76 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 24014a3c..01d36851 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,3 +1,4 @@ +/* eslint-disable no-use-before-define */ /* eslint-disable max-len */ import { defineStore } from 'pinia'; import { endpoints } from '@/constants/endpoints'; @@ -203,26 +204,33 @@ export const useMainStore = defineStore({ 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), + 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') + ...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') + ...getNonFalseValuesOfPropertyInArrayOfObjects( + state.order.lineItems.glassParts, + 'recalibrationType' + ), + ...getNonFalseValuesOfPropertyInArrayOfObjects( + state.order.lineItems.otherParts, + 'recalibrationType' + ) ] }), experimentSettings: (state) => state.applicationUser.experiments @@ -599,8 +607,7 @@ export const useMainStore = defineStore({ async getPriceOrderItems(availableLineItems) { let zipCodeToUse = this.order.serviceLocation.zipCode; let ctuToUse = this.order.serviceLocation.zipCodeCtu; - const availableLineItemsFormattedForRequest - = getLineItemQueryStringForPricing(availableLineItems); + const availableLineItemsFormattedForRequest = getLineItemQueryStringForPricing(availableLineItems); const { vehicle } = this.order; // WARNING @@ -608,8 +615,8 @@ export const useMainStore = defineStore({ // and ctu is available. Also, EON may need to be implemented. zipCodeToUse = '44902'; ctuToUse = '01820'; - const queryString - = `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` + const queryString = + `ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` + `&CTU=${ctuToUse}` + `&CarId=${vehicle.carId}` + `&Make=${vehicle.make}` @@ -637,16 +644,14 @@ export const useMainStore = defineStore({ const lineItemsWithOnlyPartNumbers = this.order.lineItems.glassParts.map((glassPart) => ({ partNumber: glassPart.partNumber })); - const lineItems = buildQueryStringParameterFromArrayOfComplexObjects(lineItemsWithOnlyPartNumbers, - 'lineItems'); + 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'); + const glassPieces = buildQueryStringParameterFromArrayOfComplexObjects(glassArray, 'glassPieces'); return globalMethods.callHttpClient({ method: endpoints.GetServiceabilityDetails.method, @@ -679,23 +684,16 @@ export const useMainStore = defineStore({ 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 + 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); + 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 @@ -927,16 +925,14 @@ export const useMainStore = defineStore({ 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; }, 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); + 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.updateGlassParts(null); @@ -954,13 +950,10 @@ export const useMainStore = defineStore({ 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); + 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.updateGlassParts(null); @@ -974,13 +967,10 @@ export const useMainStore = defineStore({ }, 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); + 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.updateGlassParts(null); @@ -1064,10 +1054,12 @@ export const useMainStore = defineStore({ endpoint: endpoints.LogPageView.url, payload, logApiCall: false - }).then((response) => response, + }).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'; } @@ -1091,10 +1083,12 @@ export const useMainStore = defineStore({ endpoint: endpoints.LogCustomEvent.url, payload, logApiCall: false - }).then((response) => response, + }).then( + (response) => response, (error) => { console.log(`Analytics Service Error: ${error.data}`); - }); + } + ); }, initializeSession({ userId, sessionId, userAgent, referrer }) { const payload = { @@ -1113,10 +1107,12 @@ export const useMainStore = defineStore({ endpoint: endpoints.InitializeSession.url, payload, logApiCall: false - }).then((response) => response, + }).then( + (response) => response, (error) => { console.log(`Analytics Service Error: ${error.data}`); - }); + } + ); }, updateLastPageVisited(lastPageVisited) { @@ -1290,19 +1286,17 @@ export const useMainStore = defineStore({ // 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; + 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' + getNonFalseValuesOfPropertyInArrayOfObjects( + state.order.lineItems.glassParts, + 'recalibrationType' + )[0].toLowerCase() !== 'unknown' ); } // Has 'requiresRecalibration' but no 'recalibrationType' at all From 81e6e3a9a62a73a07c305a4fd4c8e18ae8a7c243 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 31 Aug 2023 09:33:19 -0400 Subject: [PATCH 078/674] Adding save session after every navigation --- src/constants/coverage-statuses.js | 6 +- src/router/index.js | 12 +- .../router-constants/navigation-scenarios.js | 3 +- src/router/router-constants/routing-table.js | 4 + src/store/index.js | 64 +-- src/store/store.spec.js | 509 +++++++++++++++++- 6 files changed, 559 insertions(+), 39 deletions(-) diff --git a/src/constants/coverage-statuses.js b/src/constants/coverage-statuses.js index 5f794cc9..4142121a 100644 --- a/src/constants/coverage-statuses.js +++ b/src/constants/coverage-statuses.js @@ -1,7 +1,7 @@ const coverageStatuses = Object.freeze({ - PENDING: 'Pending', - NO_COMP: 'No Comp', - VERIFIED: 'Verified' + PENDING: 0, + NO_COMP: 1, + VERIFIED: 2 }); export default coverageStatuses; diff --git a/src/router/index.js b/src/router/index.js index 44e5e5a8..5f8f3cdc 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -82,13 +82,19 @@ const router = createRouter({ } }); -router.afterEach((to, from) => { +router.afterEach(async (to, from) => { /*eslint-disable-line*/ - const store = useMainStore(); // Update lastPageVisited in the store store.updateLastPageVisited(to.name); - store.saveSession(); + await store.saveSession()?.catch(() => { + console.log("failed :("); + if(from.name === issPageValues.WELCOME_PAGE) { + console.log("welcome!"); + router.navigate(navigationScenarios.SAVE_SESSION_FAILED, {query: {issPage: issPageValues.WELCOME_PAGE}}) + // TODO bail out if save session fails + } + }); if (to.query.issPage !== issPageValues.ENTRY_PAGE) { // Push page view to GA diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index f732786a..6fb510d2 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -11,6 +11,7 @@ const navigationScenarios = Object.freeze({ CLICKED_FORWARD_POLICY_UNVERIFIED: 'CLICKED_FORWARD_POLICY_UNVERIFIED', CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES: 'CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES', CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES: 'CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES', + SAVE_SESSION_FAILED: 'SAVE_SESSION_FAILED', // YMMS SELECTED_YEAR: 'SELECTED_YEAR', @@ -63,7 +64,7 @@ const navigationScenarios = Object.freeze({ CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: 'CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES', // Bailout - CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' + CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT', }); export default navigationScenarios; diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 4af22d4f..e2a0dc85 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -354,6 +354,10 @@ const routingTable = () => [ { scenario: navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, destinationIssPageValue: issPageValues.POLICY_VEHICLES + }, + { + scenario: navigationScenarios.SAVE_SESSION_FAILED, + destinationIssPageValue: issPageValues.BAILOUT_PAGE } ] }, diff --git a/src/store/index.js b/src/store/index.js index e89cdb27..2765a5f2 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -685,22 +685,22 @@ export const useMainStore = defineStore({ }, saveSession() { - const { vehicle, damage, policy, customer, contactInfo, payment, applicationUser, + const { vehicle, damage, policy, customer, contactInfo, payment, lineItems, serviceLocation, schedule } = this.order; const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); - return globalMethods.callHttpClient({ - method: endpoints.SaveSession.method, - endpoint: endpoints.SaveSession.url, - payload: { - applicationUser: { - crmCustomerId: applicationUser.crmCustomerId, - experiments: applicationUser.experiments, - lastPage: applicationUser.lastPageVisited, - pageData: applicationUser.pageData, - savedSessionId: applicationUser.savedSessionId - }, - order: { + 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, @@ -708,7 +708,7 @@ export const useMainStore = defineStore({ style: vehicle.style, vin: vehicle.vin, carId: vehicle.carId, - licensePlateNumber: vehicle.registration.licensePlate + licensePlateNumber: vehicle.registration?.licensePlate }, damage: { numberOfChips: damage.numberOfChips, @@ -739,11 +739,11 @@ export const useMainStore = defineStore({ }, customer: { address: { - streetAddress: customer.address.streetAddress, - streetAddress2: customer.address.streetAddress2, - city: customer.address.city, - state: customer.address.state, - zipCode: customer.address.zipCode + streetAddress: customer.address?.streetAddress, + streetAddress2: customer.address?.streetAddress2, + city: customer.address?.city, + state: customer.address?.state, + zipCode: customer.address?.zipCode }, emailAddress: contactInfo.emailAddress, firstName: contactInfo.firstName, @@ -758,8 +758,8 @@ export const useMainStore = defineStore({ }, payment: { InsuranceCoverage: { - isVerified: payment.insuranceCoverage.isVerified ?? false, - coverageStatus: payment.insuranceCoverage.coverageStatus + isVerified: payment.insuranceCoverage?.isVerified ?? false, + coverageStatus: payment.insuranceCoverage?.coverageStatus }, isInsurance: payment.isInsurance ?? true, parentAccountNumber: this.issConfig.accountNumber @@ -775,18 +775,22 @@ export const useMainStore = defineStore({ techNotes: contactInfo.notesForTechnician }, schedule: { - date: schedule?.date, - startTime: schedule?.startTime, - endTime: schedule?.endTime, - routeCode: schedule?.routeCode, - jobMaxMinutes: schedule?.jobMaxMinutes + date: schedule.date, + startTime: schedule.startTime, + endTime: schedule.endTime, + routeCode: schedule.routeCode, + jobMaxMinutes: schedule.jobMaxMinutes }, referralDate: this.order.referralDate, referralNumber: this.order.referralNumber?.toString() - } - }, - additionalSuccessEventDataHandler: (response) => - `Email provided: ${customer.emailAddress ? 'true' : 'false'}` + }, + additionalSuccessEventDataHandler: (response) => + `Email provided: ${customer.emailAddress ? 'true' : 'false'}` + }).then((response) => { + return resolve(response); + }).catch((error) => { + return reject(error); + }); }); }, diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 6a7339ef..bbaf7dc1 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -3,6 +3,7 @@ import { setActivePinia, createPinia } from 'pinia'; import globalMethods from '@/global-methods.js'; import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from '@/helpers/data-generation.js'; import coverageStatuses from '@/constants/coverage-statuses.js'; +import { endpoints } from '@/constants/endpoints'; describe('Store', () => { let store; @@ -478,6 +479,510 @@ describe('Store', () => { expect(store.contactInfo.notesForTechnician).toEqual(''); }); }); - // TODO add tests - describe('saveSession method', () => {}); + + describe('saveSession method', () => { + describe('successful method call', () => { + it('calls save session api endpoint', () => { + // Arrange + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url + } + )); + }); + it('Returns expected response object', async () => { + // Arrange + var response = { ReferralNumber: getRandomString(6, 6) }; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response)); + + // Act + const result = store.saveSession(); + + // Asserts + await expect(result).resolves.toBe(response); + }) + it('calls api with expected application user data', () => { + // Arrange + var applicationUser = { + crmCustomerId: getRandomString(6, 6), + experiments: getRandomString(6, 6), + lastPageVisited: getRandomString(6, 6), + pageData: getRandomString(6, 6), + savedSessionId: getRandomString(6, 6) + }; + store.applicationUser = applicationUser; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + const result = store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + applicationUser: expect.objectContaining({ + crmCustomerId: applicationUser.crmCustomerId, + experiments: applicationUser.experiments, + lastPage: applicationUser.lastPageVisited, + pageData: applicationUser.pageData, + savedSessionId: applicationUser.savedSessionId + }) + }) + }) + ); + }); + it('calls api with expected vehicle', () => { + var vehicle = { + year: getRandomString(6, 6), + make: getRandomString(6, 6), + model: getRandomString(6, 6), + style: getRandomString(6, 6), + carId: getRandomString(6, 6), + vin: getRandomString(6, 6), + registration: { licensePlate: getRandomString(6, 6) } + }; + store.order.vehicle = vehicle; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + vehicle: expect.objectContaining({ + year: vehicle.year, + make: vehicle.make, + model: vehicle.model, + style: vehicle.style, + carId: vehicle.carId, + vin: vehicle.vin, + licensePlateNumber: vehicle.registration.licensePlate + }) + }) + }) + } + )); + }); + it('calls api with expected damage', () => { + // Arrange + var damage = { + isRepair: getRandomString(6, 6), + numberOfChips: getRandomString(6, 6), + glassToReplace: [], + partQuestionAnswers: getRandomString(6, 6), + moldingQuestionAnswers: getRandomString(6, 6), + capabilityQuestionAnswers: getRandomString(6, 6) + }; + var policy = { + dateOfLoss: getRandomString(6, 6), + damageCause: getRandomString(6, 6), + damageState: getRandomString(6, 6), + damageCity: getRandomString(6, 6), + isDamageGlassOnly: getRandomString(6, 6) + }; + store.order.damage = damage; + store.order.policy = policy; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + damage: expect.objectContaining({ + numberOfChips: damage.numberOfChips, + 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 + }) + }) + }) + }) + ); + }); + it('calls api with expected policy', () => { + // Arrange + var customer = { + firstName: getRandomString(6, 6), + lastName: getRandomString(6, 6), + emailAddress: getRandomString(6, 6), + phoneNumber: getRandomString(6, 6) + }; + var policy = { + policyNumber: getRandomString(6, 6), + policyZipCode: getRandomString(6, 6), + policyLookupSuccessful: getRandomString(6, 6), + noCoverage: getRandomString(6, 6) + }; + var originalDeductible = getRandomString(6, 6); + var currentDeductible = getRandomString(6, 6); + store.order.originalDeductible = originalDeductible; + store.order.currentDeductible = currentDeductible; + store.order.customer = customer; + store.order.policy = policy; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + policy: expect.objectContaining({ + policyHolder: expect.objectContaining({ + policyFirstName: customer.firstName, + policyLastName: customer.lastName, + policyPhoneNumber: customer.phoneNumber, + policyEmail: customer.emailAddress + }), + policyNumber: policy.policyNumber, + policyZipCode: policy.policyZipCode, + noCoverage: policy.noCoverage, + policyLookupSuccessful: policy.policyLookupSuccessful, + originalDeductible, + currentDeductible + }) + }) + }) + }) + ); + }); + it('calls api with expected customer', () => { + // Arrange + var customer = { + address: { + streetAddress: getRandomString(6, 6), + streetAddress2: getRandomString(6, 6), + city: getRandomString(6, 6), + state: getRandomString(6, 6), + zipCode: getRandomString(6, 6) + } + }; + var contactInfo = { + firstName: getRandomString(6, 6), + lastName: getRandomString(6, 6), + emailAddress: getRandomString(6, 6), + phoneNumber: getRandomString(6, 6), + requestTextUpdates: getRandomBoolean() + }; + store.order.contactInfo = contactInfo; + store.order.customer = customer; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + customer: expect.objectContaining({ + address: expect.objectContaining({ + streetAddress: customer.address.streetAddress, + streetAddress2: customer.address.streetAddress2, + city: customer.address.city, + state: customer.address.state, + zipCode: customer.address.zipCode + }), + emailAddress: contactInfo.emailAddress, + firstName: contactInfo.firstName, + lastName: contactInfo.lastName, + phoneNumber: contactInfo.phoneNumber, + optInSms: contactInfo.requestTextUpdates + }) + }) + }) + }) + ); + }); + it('calls api with expected lineItems', () => { + // Arrange + var lineItems = { + glassParts: getRandomString(6, 6), + supportingItems: getRandomString(6, 6), + vaps: getRandomString(6, 6) + }; + store.order.lineItems = lineItems; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + lineItems: expect.objectContaining({ + glassParts: lineItems.glassParts, + supportingItems: lineItems.supportingItems, + vaps: lineItems.vaps + }) + }) + }) + }) + ); + }); + it.each([ + [coverageStatuses.PENDING], + [coverageStatuses.NO_COMP], + [coverageStatuses.VERIFIED] + ])('calls api with expected payment', (coverageStatus) => { + // Arrange + const accountNumber = getRandomString(6, 6); + const payment = { + isInsurance: getRandomBoolean(), + insuranceCoverage: { + isVerified: getRandomBoolean(), + coverageStatus + } + }; + store.issConfig.accountNumber = accountNumber; + store.order.payment = payment; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + payment: expect.objectContaining({ + InsuranceCoverage: expect.objectContaining({ + isVerified: payment.insuranceCoverage.isVerified, + coverageStatus: coverageStatus + }), + isInsurance: payment.isInsurance, + parentAccountNumber: accountNumber + }) + }) + }) + }) + ); + }); + it('calls api with expected service location', () => { + // Arrange + var notesForTechnician = getRandomString(6, 6); + var serviceLocation = { + address: getRandomString(6, 6), + city: getRandomString(6, 6), + state: getRandomString(6, 6), + zipCode: getRandomString(6, 6), + zipCodeCtu: getRandomString(6, 6) + }; + store.order.contactInfo.notesForTechnician = notesForTechnician; + store.order.serviceLocation = serviceLocation; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + serviceLocation: expect.objectContaining({ + address: expect.objectContaining({ + streetAddress: serviceLocation.address, + city: serviceLocation.city, + state: serviceLocation.state, + zipCode: serviceLocation.zipCode, + zipCodeCtu: serviceLocation.zipCodeCtu + }), + techNotes: notesForTechnician + }) + }) + }) + }) + ); + }); + it('calls api with expected schedule', () => { + // Arrange + var schedule = { + date: getRandomString(6, 6), + startTime: getRandomString(6, 6), + endTime: getRandomString(6, 6), + routeCode: getRandomString(6, 6), + jobMaxMinutes: getRandomString(6, 6) + }; + store.order.schedule = schedule; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ + schedule: expect.objectContaining({ + date: schedule.date, + startTime: schedule.startTime, + endTime: schedule.endTime, + routeCode: schedule.routeCode, + jobMaxMinutes: schedule.jobMaxMinutes + }) + }) + }) + }) + ); + }); + it('calls api with expected referral date', () => { + // Arrange + var referralDate = getRandomString(6, 6); + store.order.referralDate = referralDate; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ referralDate: referralDate }) + }) + }) + ); + }); + it('calls api with expected referral number', () => { + // Arrange + var referralNumber = getRandomString(6, 6); + store.order.referralNumber = referralNumber; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + store.saveSession(); + + // Assert + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + payload: expect.objectContaining({ + order: expect.objectContaining({ referralNumber: referralNumber }) + }) + } + )); + }); + }); + it('No glassArray => empty list', async () => { + store.damage.glassToReplace = null; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + await store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url, + payload: expect.objectContaining({ + order: expect.objectContaining({ + damage: expect.objectContaining({ + glassToReplace: [] + }) + }) + }) + }) + ); + }); + it('glassArray empty => empty list', async () => { + store.damage.glassToReplace = []; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + await store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url, + payload: expect.objectContaining({ + order: expect.objectContaining({ + damage: expect.objectContaining({ + glassToReplace: [] + }) + }) + }) + }) + ); + }); + it('Nonempty glass array => expected glass array sent', async () => { + const location1 = getRandomString(5); + const location2 = getRandomString(5); + const name1 = getRandomString(10); + const name2 = getRandomString(10); + store.damage.glassToReplace = [ + {glassLocation: location1, glassName: name1}, + {glassLocation: location2, glassName: name2} + ], + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({})); + + // Act + await store.saveSession(); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url, + payload: expect.objectContaining({ + order: expect.objectContaining({ + damage: expect.objectContaining({ + glassToReplace: expect.arrayContaining([ + {location: location1, name: name1}, + {location: location2, name: name2} + ]) + }) + }) + }) + }) + ); + }); + it('api call throws exception', async () => { + expect.assertions(2); + const error = 'this is the error'; + globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject(error)); + + // Act + await store.saveSession().catch((e) => { + expect(e).toEqual(error); + }); + + // Asserts + expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( + { + method: endpoints.SaveSession.method, + endpoint: endpoints.SaveSession.url + }) + ); + }); + }); }); From df86541d30a2f5db9040c429f41de6d6f366c909 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 31 Aug 2023 09:40:30 -0400 Subject: [PATCH 079/674] Removing comments --- src/router/index.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index 5f8f3cdc..6406096d 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -88,11 +88,8 @@ router.afterEach(async (to, from) => { // Update lastPageVisited in the store store.updateLastPageVisited(to.name); await store.saveSession()?.catch(() => { - console.log("failed :("); if(from.name === issPageValues.WELCOME_PAGE) { - console.log("welcome!"); router.navigate(navigationScenarios.SAVE_SESSION_FAILED, {query: {issPage: issPageValues.WELCOME_PAGE}}) - // TODO bail out if save session fails } }); From cc893b6eacc8d217e295b83ca0e4d4da3fafcb73 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Thu, 31 Aug 2023 13:16:44 -0400 Subject: [PATCH 080/674] clear error list on enable/disable --- .../dropdown-question/dropdown-question.vue | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/digital-components/dropdown-question/dropdown-question.vue b/src/digital-components/dropdown-question/dropdown-question.vue index 25a850d2..05f8b9a4 100644 --- a/src/digital-components/dropdown-question/dropdown-question.vue +++ b/src/digital-components/dropdown-question/dropdown-question.vue @@ -79,14 +79,19 @@ export default { initialValue }; - const { errorMessage, handleBlur, handleChange, meta, errors } = useField(props.inputId, props.validationRules, fieldOptions); + const { errorMessage, + handleBlur, + handleChange, + meta, errors, + setErrors } = useField(props.inputId, props.validationRules, fieldOptions); return { errorMessage, handleBlur, handleChange, meta, - errors + errors, + setErrors }; }, computed: { @@ -123,6 +128,11 @@ export default { } }, watch: { + isDisabled(newValue, oldValue) { + if (newValue !== oldValue) { + this.setErrors([]); + } + }, selectedOption(newValue) { this.handleChange(newValue); } From 7442e48ba52342dc422aced1ec95059abfe078c4 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 31 Aug 2023 13:27:58 -0400 Subject: [PATCH 081/674] Setting values based on save session output --- src/store/index.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 2765a5f2..b2b9d9df 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -92,8 +92,6 @@ const getDefaultState = () => ({ coverageStatus: coverageStatuses.PENDING } }, - referralNumber: null, - referralDate: null, contactInfo: { firstName: null, lastName: null, @@ -108,7 +106,13 @@ const getDefaultState = () => ({ endTime: null, routeCode: null, jobMaxMinutes: null - } + }, + referralNumber: null, + referralDate: null, + referralCorrelationId: null, + referralSequenceNumber: null, + eon: null, + workOrderNumber: null }, applicationUser: { experiments: [], @@ -782,11 +786,24 @@ export const useMainStore = defineStore({ jobMaxMinutes: schedule.jobMaxMinutes }, referralDate: this.order.referralDate, - referralNumber: this.order.referralNumber?.toString() + referralNumber: this.order.referralNumber?.toString(), + referralCorrelationId: this.order.referralCorrelationId, + referralSequenceNumber: this.order.referralSequenceNumber, + eon: this.order.eon }, additionalSuccessEventDataHandler: (response) => `Email provided: ${customer.emailAddress ? 'true' : 'false'}` }).then((response) => { + if (referralNumber === null) { + 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; + } return resolve(response); }).catch((error) => { return reject(error); From 81ec8d4d1485d76d3b1f59ad980b91453c2dfb79 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 31 Aug 2023 16:11:53 -0400 Subject: [PATCH 082/674] Committing to facilitate collab --- src/helpers/cookie-helper.js | 5 +- src/helpers/order-helper.js | 60 +++++++++ src/router/index.js | 13 +- src/store/index.js | 237 +++++++++++++++++------------------ 4 files changed, 190 insertions(+), 125 deletions(-) create mode 100644 src/helpers/order-helper.js diff --git a/src/helpers/cookie-helper.js b/src/helpers/cookie-helper.js index 2b93484b..bf88ace6 100644 --- a/src/helpers/cookie-helper.js +++ b/src/helpers/cookie-helper.js @@ -112,7 +112,9 @@ function setISSCookieProperties(properties) { Will update the cookie if present, or create a new one if not. */ export function updateOrCreateISSCookie() { + console.log('in cookie function'); const store = useMainStore(); + console.log(store); // Set up cookie with all the props. setISSCookieProperties({ @@ -122,7 +124,8 @@ export function updateOrCreateISSCookie() { ReferralNumber: store.order.referralNumber, ReferralDate: store.order.referralDate, ReferralCorrelationId: store.order.referralCorrelationId, - ReferralParentAccountNumber: store.order.accountNumber + ReferralParentAccountNumber: store.order.accountNumber, + SavedSessionId: store.applicationUser.savedSessionId }); } diff --git a/src/helpers/order-helper.js b/src/helpers/order-helper.js new file mode 100644 index 00000000..290b4c0e --- /dev/null +++ b/src/helpers/order-helper.js @@ -0,0 +1,60 @@ +import { useMainStore } from '@/store'; +import { updateOrCreateISSCookie } from '@/helpers/cookie-helper'; + +/* + Will call API to save existing order, or create new one depending where it's called from. + This will also set Referral information in the store after saving, and then + update the cookie. To force synchronous behavior pass in 'true' for shouldAwaitSaveSessionQueue +*/ +// encapsulate when you transition back into heritage +// we need eon from first call to get pricing +// eon is a number that some services require +// save session takes time +// not necessary for much throughout the flow +// we want each save session call to happen sequentially, but asynchronously +export async function saveSession({ shouldAwaitSaveSessionQueue = false }) { + const store = useMainStore(); + console.log('order helper'); + console.log(store); + var saveSessionPromise; + if (store.applicationUser.saveSessionPromise){ + console.log('if promise exists'); + console.log(store.applicationUser.saveSessionPromise); + + // .then returns another promise but waiting for another to finish + saveSessionPromise = store.applicationUser.saveSessionPromise + .then(() => { + console.log('then'); + return saveSessionHelper(store); + }) + .catch((error) => { + console.log("saveSessionPromise failed: " + error.message); + }); + } + else { + console.log('else'); + saveSessionPromise = saveSessionHelper(store); + } + // var saveSessionPromise = + // store.applicationUser.saveSessionPromise + // ? store.applicationUser.saveSessionPromise.then(() => { return saveSessionHelper(store); }) + // : saveSessionHelper(store); + console.log('promise exists'); + store.setSaveSessionPromise(saveSessionPromise); + console.log('set information'); + if (!store.applicationUser.savedSessionId || shouldAwaitSaveSessionQueue) { + console.log('pre await'); + await saveSessionPromise; + } + console.log('done'); +} + +/* + Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing +*/ +async function saveSessionHelper(store) { + console.log('helper helper called'); + const savedSessionInfo = await store.saveSession(); + store.setSaveSessionInfo(savedSessionInfo.data); + updateOrCreateISSCookie(); +} \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 6406096d..be341fbb 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -16,6 +16,7 @@ import applicationConfig from '@/constants/application-config'; import analyticsMixin from '@/mixins/analytics-mixin'; import navigationScenarios from './router-constants/navigation-scenarios'; +import { saveSession } from "@/helpers/order-helper.js"; const routes = [ { @@ -87,12 +88,18 @@ router.afterEach(async (to, from) => { const store = useMainStore(); // Update lastPageVisited in the store store.updateLastPageVisited(to.name); - await store.saveSession()?.catch(() => { - if(from.name === issPageValues.WELCOME_PAGE) { + console.log('after each'); + + await saveSession({shouldAwaitSaveSessionQueue: true}).then(() => { + console.log('then'); + }).catch((error) => { + console.log(error); + console.log("catch"); + if (from.name === issPageValues.WELCOME_PAGE) { router.navigate(navigationScenarios.SAVE_SESSION_FAILED, {query: {issPage: issPageValues.WELCOME_PAGE}}) } }); - + if (to.query.issPage !== issPageValues.ENTRY_PAGE) { // Push page view to GA analyticsMixin.methods.pushPageViewToGA(); diff --git a/src/store/index.js b/src/store/index.js index b2b9d9df..35a71604 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -109,7 +109,7 @@ const getDefaultState = () => ({ }, referralNumber: null, referralDate: null, - referralCorrelationId: null, + referralCorrelationId: '00000000-0000-0000-0000-000000000000', referralSequenceNumber: null, eon: null, workOrderNumber: null @@ -338,8 +338,6 @@ export const useMainStore = defineStore({ } }, getCoveragePolicyInfo({ accountNumber, policyNumber, dateOfLoss, zipCode }) { - // TODO: replace place holder correlationId with the real thing - const placeHolderCorrelationId = '00000000-0000-0000-0000-000000000000'; const { policy } = this.order; try { const response = globalMethods.callHttpClient({ @@ -350,7 +348,7 @@ export const useMainStore = defineStore({ policyNumber, dateOfLoss, zipCode, - correlationId: placeHolderCorrelationId + correlationId: this.order.referralCorrelationId } }).then((r) => { const responsePolicy = r.data.policies?.[0]; @@ -371,8 +369,6 @@ export const useMainStore = defineStore({ } }, registerClaim() { - // TODO: replace place holder correlationId with the real thing - const placeHolderCorrelationId = '00000000-0000-0000-0000-000000000000'; const nonNumberCharRegex = /[^0-9]/g; const { order } = this; return new Promise((resolve, reject) => { @@ -381,7 +377,7 @@ export const useMainStore = defineStore({ endpoint: endpoints.RegisterClaim.url, payload: { - correlationId: placeHolderCorrelationId, + correlationId: this.order.referralCorrelationId, accountNumber: this.issConfig.accountNumber?.toString() ?? '', insured: { firstName: this.order.customer.firstName, @@ -688,129 +684,128 @@ export const useMainStore = defineStore({ }); }, + 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; 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 - }, - policyNumber: policy.policyNumber, - policyZipCode: policy.policyZipCode, - noCoverage: policy.noCoverage, - policyLookupSuccessful: policy.policyLookupSuccessful, - originalDeductible: this.order.originalDeductible, - currentDeductible: this.order.currentDeductible - }, - customer: { - address: { - streetAddress: customer.address?.streetAddress, - streetAddress2: customer.address?.streetAddress2, - city: customer.address?.city, - state: customer.address?.state, - zipCode: customer.address?.zipCode - }, - emailAddress: contactInfo.emailAddress, - firstName: contactInfo.firstName, - lastName: contactInfo.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 - }, - isInsurance: payment.isInsurance ?? true, - parentAccountNumber: this.issConfig.accountNumber - }, - serviceLocation: { - address: { - streetAddress: serviceLocation.address, - city: serviceLocation.city, - state: serviceLocation.state, - zipCode: serviceLocation.zipCode, - zipCodeCtu: serviceLocation.zipCodeCtu - }, - techNotes: contactInfo.notesForTechnician - }, - schedule: { - date: schedule.date, - startTime: schedule.startTime, - endTime: schedule.endTime, - routeCode: schedule.routeCode, - jobMaxMinutes: schedule.jobMaxMinutes - }, - referralDate: this.order.referralDate, - referralNumber: this.order.referralNumber?.toString(), - referralCorrelationId: this.order.referralCorrelationId, - referralSequenceNumber: this.order.referralSequenceNumber, - eon: this.order.eon + return 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 }, - additionalSuccessEventDataHandler: (response) => - `Email provided: ${customer.emailAddress ? 'true' : 'false'}` - }).then((response) => { - if (referralNumber === null) { - 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; - } - return resolve(response); - }).catch((error) => { - return reject(error); - }); + 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 + }, + policyNumber: policy.policyNumber, + policyZipCode: policy.policyZipCode, + noCoverage: policy.noCoverage, + policyLookupSuccessful: policy.policyLookupSuccessful, + originalDeductible: this.order.originalDeductible, + currentDeductible: this.order.currentDeductible + }, + customer: { + address: { + streetAddress: customer.address?.streetAddress, + streetAddress2: customer.address?.streetAddress2, + city: customer.address?.city, + state: customer.address?.state, + zipCode: customer.address?.zipCode + }, + emailAddress: contactInfo.emailAddress, + firstName: contactInfo.firstName, + lastName: contactInfo.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 + }, + isInsurance: payment.isInsurance ?? true, + parentAccountNumber: this.issConfig.accountNumber + }, + serviceLocation: { + address: { + streetAddress: serviceLocation.address, + city: serviceLocation.city, + state: serviceLocation.state, + zipCode: serviceLocation.zipCode, + zipCodeCtu: serviceLocation.zipCodeCtu + }, + techNotes: contactInfo.notesForTechnician + }, + schedule: { + date: schedule.date, + startTime: schedule.startTime, + endTime: schedule.endTime, + routeCode: schedule.routeCode, + jobMaxMinutes: schedule.jobMaxMinutes + }, + referralDate: this.order.referralDate, + referralNumber: this.order.referralNumber?.toString(), + referralCorrelationId: this.order.referralCorrelationId, + referralSequenceNumber: this.order.referralSequenceNumber, + eon: this.order.eon + }, + additionalSuccessEventDataHandler: (response) => + `Email provided: ${customer.emailAddress ? 'true' : 'false'}` }); }, + setSaveSessionPromise(promise){ + this.applicationUser.saveSessionPromise = promise; + }, + saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) { const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort(); const isGlassToReplaceTheSame From 9118d598786975dd103eefd220dea2b9d8ca4c53 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 31 Aug 2023 16:27:35 -0400 Subject: [PATCH 083/674] Addressing problems --- src/helpers/cookie-helper.js | 2 -- src/helpers/order-helper.js | 39 ++++-------------------------------- src/router/index.js | 11 +++++----- src/store/index.js | 4 ++++ 4 files changed, 13 insertions(+), 43 deletions(-) diff --git a/src/helpers/cookie-helper.js b/src/helpers/cookie-helper.js index bf88ace6..0fb14dd3 100644 --- a/src/helpers/cookie-helper.js +++ b/src/helpers/cookie-helper.js @@ -112,9 +112,7 @@ function setISSCookieProperties(properties) { Will update the cookie if present, or create a new one if not. */ export function updateOrCreateISSCookie() { - console.log('in cookie function'); const store = useMainStore(); - console.log(store); // Set up cookie with all the props. setISSCookieProperties({ diff --git a/src/helpers/order-helper.js b/src/helpers/order-helper.js index 290b4c0e..0b89d8e5 100644 --- a/src/helpers/order-helper.js +++ b/src/helpers/order-helper.js @@ -6,54 +6,23 @@ import { updateOrCreateISSCookie } from '@/helpers/cookie-helper'; This will also set Referral information in the store after saving, and then update the cookie. To force synchronous behavior pass in 'true' for shouldAwaitSaveSessionQueue */ -// encapsulate when you transition back into heritage -// we need eon from first call to get pricing -// eon is a number that some services require -// save session takes time -// not necessary for much throughout the flow -// we want each save session call to happen sequentially, but asynchronously export async function saveSession({ shouldAwaitSaveSessionQueue = false }) { const store = useMainStore(); - console.log('order helper'); - console.log(store); - var saveSessionPromise; - if (store.applicationUser.saveSessionPromise){ - console.log('if promise exists'); - console.log(store.applicationUser.saveSessionPromise); + var saveSessionPromise = store.applicationUser.saveSessionPromise + ? store.applicationUser.saveSessionPromise.then(() => { return saveSessionHelper(store); }) + : saveSessionHelper(store); - // .then returns another promise but waiting for another to finish - saveSessionPromise = store.applicationUser.saveSessionPromise - .then(() => { - console.log('then'); - return saveSessionHelper(store); - }) - .catch((error) => { - console.log("saveSessionPromise failed: " + error.message); - }); - } - else { - console.log('else'); - saveSessionPromise = saveSessionHelper(store); - } - // var saveSessionPromise = - // store.applicationUser.saveSessionPromise - // ? store.applicationUser.saveSessionPromise.then(() => { return saveSessionHelper(store); }) - // : saveSessionHelper(store); - console.log('promise exists'); store.setSaveSessionPromise(saveSessionPromise); - console.log('set information'); + if (!store.applicationUser.savedSessionId || shouldAwaitSaveSessionQueue) { - console.log('pre await'); await saveSessionPromise; } - console.log('done'); } /* Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing */ async function saveSessionHelper(store) { - console.log('helper helper called'); const savedSessionInfo = await store.saveSession(); store.setSaveSessionInfo(savedSessionInfo.data); updateOrCreateISSCookie(); diff --git a/src/router/index.js b/src/router/index.js index be341fbb..a2efe1a7 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -88,13 +88,12 @@ router.afterEach(async (to, from) => { const store = useMainStore(); // Update lastPageVisited in the store store.updateLastPageVisited(to.name); - console.log('after each'); + + if (from.redirectedFrom == undefined){ + store.clearSaveSessionPromise(); + } - await saveSession({shouldAwaitSaveSessionQueue: true}).then(() => { - console.log('then'); - }).catch((error) => { - console.log(error); - console.log("catch"); + await saveSession({shouldAwaitSaveSessionQueue: true}).catch((error) => { if (from.name === issPageValues.WELCOME_PAGE) { router.navigate(navigationScenarios.SAVE_SESSION_FAILED, {query: {issPage: issPageValues.WELCOME_PAGE}}) } diff --git a/src/store/index.js b/src/store/index.js index 35a71604..d5587220 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -806,6 +806,10 @@ export const useMainStore = defineStore({ this.applicationUser.saveSessionPromise = promise; }, + clearSaveSessionPromise(){ + this.applicationUser.saveSessionPromise = null; + }, + saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) { const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort(); const isGlassToReplaceTheSame From 8bbd7afb776dec8aabd012fd09485686d00ea2c1 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 31 Aug 2023 16:53:53 -0400 Subject: [PATCH 084/674] Adding parameter to indicate whether save session should be synchronous --- src/router/index.js | 8 ++++++-- src/router/router-constants/router-params.js | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index a2efe1a7..de100b55 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -17,6 +17,7 @@ import applicationConfig from '@/constants/application-config'; import analyticsMixin from '@/mixins/analytics-mixin'; import navigationScenarios from './router-constants/navigation-scenarios'; import { saveSession } from "@/helpers/order-helper.js"; +import routerParams from '@/router/router-constants/router-params'; const routes = [ { @@ -93,9 +94,12 @@ router.afterEach(async (to, from) => { store.clearSaveSessionPromise(); } - await saveSession({shouldAwaitSaveSessionQueue: true}).catch((error) => { + const saveSessionSynchronous = !!from.params[routerParams.SAVE_SESSION_SYNCHRONOUS]; + await saveSession({shouldAwaitSaveSessionQueue: saveSessionSynchronous}).catch((error) => { if (from.name === issPageValues.WELCOME_PAGE) { - router.navigate(navigationScenarios.SAVE_SESSION_FAILED, {query: {issPage: issPageValues.WELCOME_PAGE}}) + router.navigate( + navigationScenarios.SAVE_SESSION_FAILED, + {query: {issPage: issPageValues.WELCOME_PAGE}}); } }); diff --git a/src/router/router-constants/router-params.js b/src/router/router-constants/router-params.js index 37b1300d..2465f965 100644 --- a/src/router/router-constants/router-params.js +++ b/src/router/router-constants/router-params.js @@ -1,5 +1,6 @@ const routerParams = Object.freeze({ - DISPLAY_VEHICLE_CHANGE_ALERT: 'displayVehicleChangeAlert' + DISPLAY_VEHICLE_CHANGE_ALERT: 'displayVehicleChangeAlert', + SAVE_SESSION_SYNCHRONOUS: 'saveSessionSynchronous' }); export default routerParams; From 5db1b97e1b832eb5b644197c29038f1c394b38dc Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 31 Aug 2023 17:00:29 -0400 Subject: [PATCH 085/674] Reverting unnecessary changes --- src/router/router-constants/navigation-scenarios.js | 2 +- src/store/index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 6fb510d2..38b59ba9 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -64,7 +64,7 @@ const navigationScenarios = Object.freeze({ CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: 'CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES', // Bailout - CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT', + CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' }); export default navigationScenarios; diff --git a/src/store/index.js b/src/store/index.js index d5587220..69dcfd3c 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1303,14 +1303,14 @@ export const useMainStore = defineStore({ }, async validateZip({ zip }) { - return globalMethods.callHttpClient({ + return await globalMethods.callHttpClient({ methods: endpoints.ValidateZip.method, endpoint: `${endpoints.ValidateZip.url}/${zip}` }); }, async validateClientTag(clientTag) { - return globalMethods.callHttpClient({ + return await globalMethods.callHttpClient({ methods: endpoints.ValidateClientTag.method, endpoint: `${endpoints.ValidateClientTag.url}/${clientTag}` }); From 40c381fdb87dffc24091faed2f57be3821ebc033 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 11:07:57 -0400 Subject: [PATCH 086/674] Fixing tests --- src/store/store.spec.js | 196 +++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 114 deletions(-) diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 03427c95..d03784f5 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -560,16 +560,14 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { payload: expect.objectContaining({ - order: expect.objectContaining({ - vehicle: expect.objectContaining({ - year: vehicle.year, - make: vehicle.make, - model: vehicle.model, - style: vehicle.style, - carId: vehicle.carId, - vin: vehicle.vin, - licensePlateNumber: vehicle.registration.licensePlate - }) + vehicle: expect.objectContaining({ + year: vehicle.year, + make: vehicle.make, + model: vehicle.model, + style: vehicle.style, + carId: vehicle.carId, + vin: vehicle.vin, + licensePlateNumber: vehicle.registration.licensePlate }) }) } @@ -603,19 +601,17 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { payload: expect.objectContaining({ - order: expect.objectContaining({ - damage: expect.objectContaining({ - numberOfChips: damage.numberOfChips, - 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 - }) + damage: expect.objectContaining({ + numberOfChips: damage.numberOfChips, + 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 }) }) }) @@ -650,21 +646,19 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { payload: expect.objectContaining({ - order: expect.objectContaining({ - policy: expect.objectContaining({ - policyHolder: expect.objectContaining({ - policyFirstName: customer.firstName, - policyLastName: customer.lastName, - policyPhoneNumber: customer.phoneNumber, - policyEmail: customer.emailAddress - }), - policyNumber: policy.policyNumber, - policyZipCode: policy.policyZipCode, - noCoverage: policy.noCoverage, - policyLookupSuccessful: policy.policyLookupSuccessful, - originalDeductible, - currentDeductible - }) + policy: expect.objectContaining({ + policyHolder: expect.objectContaining({ + policyFirstName: customer.firstName, + policyLastName: customer.lastName, + policyPhoneNumber: customer.phoneNumber, + policyEmail: customer.emailAddress + }), + policyNumber: policy.policyNumber, + policyZipCode: policy.policyZipCode, + noCoverage: policy.noCoverage, + policyLookupSuccessful: policy.policyLookupSuccessful, + originalDeductible, + currentDeductible }) }) }) @@ -699,21 +693,19 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { payload: expect.objectContaining({ - order: expect.objectContaining({ - customer: expect.objectContaining({ - address: expect.objectContaining({ - streetAddress: customer.address.streetAddress, - streetAddress2: customer.address.streetAddress2, - city: customer.address.city, - state: customer.address.state, - zipCode: customer.address.zipCode - }), - emailAddress: contactInfo.emailAddress, - firstName: contactInfo.firstName, - lastName: contactInfo.lastName, - phoneNumber: contactInfo.phoneNumber, - optInSms: contactInfo.requestTextUpdates - }) + customer: expect.objectContaining({ + address: expect.objectContaining({ + streetAddress: customer.address.streetAddress, + streetAddress2: customer.address.streetAddress2, + city: customer.address.city, + state: customer.address.state, + zipCode: customer.address.zipCode + }), + emailAddress: contactInfo.emailAddress, + firstName: contactInfo.firstName, + lastName: contactInfo.lastName, + phoneNumber: contactInfo.phoneNumber, + optInSms: contactInfo.requestTextUpdates }) }) }) @@ -736,12 +728,10 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { payload: expect.objectContaining({ - order: expect.objectContaining({ - lineItems: expect.objectContaining({ - glassParts: lineItems.glassParts, - supportingItems: lineItems.supportingItems, - vaps: lineItems.vaps - }) + lineItems: expect.objectContaining({ + glassParts: lineItems.glassParts, + supportingItems: lineItems.supportingItems, + vaps: lineItems.vaps }) }) }) @@ -772,15 +762,13 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { payload: expect.objectContaining({ - order: expect.objectContaining({ - payment: expect.objectContaining({ - InsuranceCoverage: expect.objectContaining({ - isVerified: payment.insuranceCoverage.isVerified, - coverageStatus: coverageStatus - }), - isInsurance: payment.isInsurance, - parentAccountNumber: accountNumber - }) + payment: expect.objectContaining({ + InsuranceCoverage: expect.objectContaining({ + isVerified: payment.insuranceCoverage.isVerified, + coverageStatus: coverageStatus + }), + isInsurance: payment.isInsurance, + parentAccountNumber: accountNumber }) }) }) @@ -807,17 +795,15 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { payload: expect.objectContaining({ - order: expect.objectContaining({ - serviceLocation: expect.objectContaining({ - address: expect.objectContaining({ - streetAddress: serviceLocation.address, - city: serviceLocation.city, - state: serviceLocation.state, - zipCode: serviceLocation.zipCode, - zipCodeCtu: serviceLocation.zipCodeCtu - }), - techNotes: notesForTechnician - }) + serviceLocation: expect.objectContaining({ + address: expect.objectContaining({ + streetAddress: serviceLocation.address, + city: serviceLocation.city, + state: serviceLocation.state, + zipCode: serviceLocation.zipCode, + zipCodeCtu: serviceLocation.zipCodeCtu + }), + techNotes: notesForTechnician }) }) }) @@ -842,14 +828,12 @@ describe('Store', () => { expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { payload: expect.objectContaining({ - order: expect.objectContaining({ - schedule: expect.objectContaining({ - date: schedule.date, - startTime: schedule.startTime, - endTime: schedule.endTime, - routeCode: schedule.routeCode, - jobMaxMinutes: schedule.jobMaxMinutes - }) + schedule: expect.objectContaining({ + date: schedule.date, + startTime: schedule.startTime, + endTime: schedule.endTime, + routeCode: schedule.routeCode, + jobMaxMinutes: schedule.jobMaxMinutes }) }) }) @@ -867,9 +851,7 @@ describe('Store', () => { // Assert expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { - payload: expect.objectContaining({ - order: expect.objectContaining({ referralDate: referralDate }) - }) + payload: expect.objectContaining({ referralDate: referralDate }) }) ); }); @@ -885,9 +867,7 @@ describe('Store', () => { // Assert expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { - payload: expect.objectContaining({ - order: expect.objectContaining({ referralNumber: referralNumber }) - }) + payload: expect.objectContaining({ referralNumber: referralNumber }) } )); }); @@ -902,13 +882,9 @@ describe('Store', () => { // Asserts expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { - method: endpoints.SaveSession.method, - endpoint: endpoints.SaveSession.url, payload: expect.objectContaining({ - order: expect.objectContaining({ - damage: expect.objectContaining({ - glassToReplace: [] - }) + damage: expect.objectContaining({ + glassToReplace: [] }) }) }) @@ -924,13 +900,9 @@ describe('Store', () => { // Asserts expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { - method: endpoints.SaveSession.method, - endpoint: endpoints.SaveSession.url, payload: expect.objectContaining({ - order: expect.objectContaining({ - damage: expect.objectContaining({ - glassToReplace: [] - }) + damage: expect.objectContaining({ + glassToReplace: [] }) }) }) @@ -953,16 +925,12 @@ describe('Store', () => { // Asserts expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining( { - method: endpoints.SaveSession.method, - endpoint: endpoints.SaveSession.url, payload: expect.objectContaining({ - order: expect.objectContaining({ - damage: expect.objectContaining({ - glassToReplace: expect.arrayContaining([ - {location: location1, name: name1}, - {location: location2, name: name2} - ]) - }) + damage: expect.objectContaining({ + glassToReplace: expect.arrayContaining([ + {location: location1, name: name1}, + {location: location2, name: name2} + ]) }) }) }) From b0353cf7f7df10dae7a46f0810f0daaca778c1f8 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 11:15:38 -0400 Subject: [PATCH 087/674] Setting current and original deductible --- src/store/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index fa0e4c0d..c582e318 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -113,7 +113,9 @@ const getDefaultState = () => ({ referralCorrelationId: '00000000-0000-0000-0000-000000000000', referralSequenceNumber: null, eon: null, - workOrderNumber: null + workOrderNumber: null, + originalDeductible: null, + currentDeductible: null }, applicationUser: { experiments: [], @@ -898,6 +900,10 @@ export const useMainStore = defineStore({ this.order.policy.deductible.replace = vehicle.deductible; this.order.policy.deductible.repair = vehicle?.repairWaived ?? false ? 0 : vehicle.deductible; + // TODO logic should be more complicated later on + this.order.originalDeductible = vehicle.deductible; + this.order.currentDeductible = vehicle.deductible; + this.resetSupportingItemsState(); this.resetVapsState(); }, From 412b2bebb6e651c09874cd972b36e0bb34213e2e Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 12:06:20 -0400 Subject: [PATCH 088/674] Swapping store call --- src/layouts/address-lookup/address-lookup.vue | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue index 5f913011..9f86be4e 100644 --- a/src/layouts/address-lookup/address-lookup.vue +++ b/src/layouts/address-lookup/address-lookup.vue @@ -92,7 +92,7 @@ import routerParams from '@/router/router-constants/router-params'; import { getDamageString, isGlassAvailableForCarId } from '@/helpers/damage-helper'; import vinPagesMixin from '@/mixins/vin-pages-mixin'; -import { useMainStore } from '@/store'; +import { useMainStore } from '@/store/index.js'; export default { name: 'address-lookup', @@ -152,7 +152,7 @@ export default { // eslint-disable-next-line max-len `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`; const vinYmmExpected = - `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`; + `${useMainStore().order.vehicle.year} ${useMainStore().order.vehicle.make} ${useMainStore().order.vehicle.model}`; return this.getCmsContent('AlertMatchedDifferentVehicleWidget', 'BodyText') .replaceAll('{custom:damage}', getDamageString()) @@ -171,7 +171,7 @@ export default { `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model} ${this.customAlertData?.vehicleInfo?.style}`; const vinYmmsExpected = // eslint-disable-next-line max-len - `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model} ${this.mainStore.order.vehicle.style}`; + `${useMainStore().order.vehicle.year} ${useMainStore().order.vehicle.make} ${useMainStore().order.vehicle.model} ${useMainStore().order.vehicle.style}`; return this.getCmsContent('AlertMatchedTwoIdenticalYMMVehicleWidget', 'BodyText') .replaceAll('{custom:damage}', getDamageString()) @@ -183,7 +183,7 @@ export default { // eslint-disable-next-line max-len `${this.customAlertData?.vehicleInfo?.year} ${this.customAlertData?.vehicleInfo?.make} ${this.customAlertData?.vehicleInfo?.model}`; const vinYmmExpected = - `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`; + `${useMainStore().order.vehicle.year} ${useMainStore().order.vehicle.make} ${useMainStore().order.vehicle.model}`; return (vinYmmFound.toLowerCase() === vinYmmExpected.toLowerCase()); } }, @@ -203,7 +203,7 @@ export default { }, methods: { arePagePrerequisitesValid() { - return this.mainStore.order.vehicle.carId !== null; + return useMainStore().order.vehicle.carId !== null; }, backButtonAction() { @@ -283,7 +283,7 @@ export default { vehicleInfoToCommit = Object.assign(carFound, { vin: carsFound[0].vin }); } else if (carsFound.length > 1) { // If multiple cars were found and one and only one of them matches the carId entered, save the vehicle info - const matchingCars = carsFound.filter((vin) => vin.vehicle.carId === this.mainStore.order.vehicle.carId); + const matchingCars = carsFound.filter((vin) => vin.vehicle.carId === useMainStore().order.vehicle.carId); if (matchingCars.length === 1) { vehicleInfoToCommit = Object.assign(matchingCars[0].vehicle, { From a511a550bf296d4ed98884231f3ccf0dcb51af01 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 12:18:57 -0400 Subject: [PATCH 089/674] Fixing store reference in remaining prerequisites --- src/layouts/address-vehicles/address-vehicles.vue | 2 +- src/layouts/license-plate-lookup/license-plate-lookup.vue | 2 +- src/layouts/vehicle-parts/vehicle-parts.vue | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/layouts/address-vehicles/address-vehicles.vue b/src/layouts/address-vehicles/address-vehicles.vue index 63cb3572..4494d938 100644 --- a/src/layouts/address-vehicles/address-vehicles.vue +++ b/src/layouts/address-vehicles/address-vehicles.vue @@ -226,7 +226,7 @@ export default { getRouterLinkRouteFromCopy, getRouterLinkDisplayTextFromCopy, arePagePrerequisitesValid() { - if (this.mainStore.order.vehicle.carId) { + if (useMainStore().order.vehicle.carId) { return true; } return false; diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue index 91d70b2b..a1b46623 100644 --- a/src/layouts/license-plate-lookup/license-plate-lookup.vue +++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue @@ -218,7 +218,7 @@ export default { }, methods: { arePagePrerequisitesValid() { - return this.mainStore.order.vehicle.carId !== null; + return useMainStore().order.vehicle.carId !== null; }, loadDefaultsFromStore() { this.customerQuestions = this.mainStore.customerData.addressQuestions.state; diff --git a/src/layouts/vehicle-parts/vehicle-parts.vue b/src/layouts/vehicle-parts/vehicle-parts.vue index 7848c4e3..52b33ed8 100644 --- a/src/layouts/vehicle-parts/vehicle-parts.vue +++ b/src/layouts/vehicle-parts/vehicle-parts.vue @@ -77,6 +77,7 @@ import issPageValues from '@/router/router-constants/issPage-values'; import { Form } from 'vee-validate'; import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; +import { useMainStore } from '@/store'; export default { name: 'vehicle-parts', @@ -178,9 +179,9 @@ export default { arePagePrerequisitesValid() { // Check if isRepair is populated and if the pageData we need is here (Parts data) return ( - this.mainStore.damage.isRepair != null - && this.mainStore.pageData(issPageValues.VEHICLE_PARTS) - && Object.keys(this.mainStore.pageData(issPageValues.VEHICLE_PARTS)).length !== 0 + useMainStore().damage.isRepair != null + && useMainStore().pageData(issPageValues.VEHICLE_PARTS) + && Object.keys(useMainStore().pageData(issPageValues.VEHICLE_PARTS)).length !== 0 ); }, async forwardButtonAction() { From 6043b0ce8f03037270c3e1b6b5b54b98d3e80dc9 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 12:42:05 -0400 Subject: [PATCH 090/674] Swapping loose equality for strict --- src/router/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router/index.js b/src/router/index.js index e5eeee1e..30539023 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -124,7 +124,7 @@ router.afterEach(async (to, from) => { // Update lastPageVisited in the store store.updateLastPageVisited(to.name); - if (from.redirectedFrom == undefined){ + if (from.redirectedFrom === undefined){ store.clearSaveSessionPromise(); } From 083cef3b85afd3e49c3b94a2d089a17891a99417 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 12:51:56 -0400 Subject: [PATCH 091/674] save session synchronous after welcome page and coverage statement page --- .../coverage-statement/coverage-statement.vue | 20 ++++++++++++++----- src/layouts/welcome-page/welcome-page.vue | 10 +++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index f27b2208..6dce9a1b 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -337,29 +337,39 @@ export default { if (this.unverified || this.verifiedDeductible) { this.$router.navigate( navigationScenarios.CLICKED_FORWARD, - this.$route + this.$route, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else if (this.verifiedITAC || this.verifiedNoComp) { if (this.selectedProvider === 'Safelite') { this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, - this.$route + this.$route, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else if (useMainStore().issConfig.enableTPAFlow) { this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED, - this.$route + this.$route, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else { this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED, - this.$route + this.$route, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } } else { this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE, - this.$route + this.$route, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } }, diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index e9943ba6..45666547 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -351,7 +351,7 @@ export default { this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, this.$route, {}, - {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }, this.vehiclesFound ); } else { @@ -359,14 +359,18 @@ export default { // navigate to vehicle-selection page (manual entry) this.$router.navigate( this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, - this.$route + this.$route, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } } else { // if policy lookup is unsuccessful, navigate to policy-holder-details page this.$router.navigate( this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED, - this.$route + this.$route, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } }, From da44fe9e1caec3b76371e2480370b63e17f1c685 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 12:53:04 -0400 Subject: [PATCH 092/674] Adding routerParams reference --- src/layouts/coverage-statement/coverage-statement.vue | 1 + src/layouts/welcome-page/welcome-page.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 6dce9a1b..ccd03999 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -120,6 +120,7 @@ import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin.js'; import globalRules from '@/constants/global-rules.js'; import baseFormMixin from '@/mixins/base-form-mixin.js'; import navigationScenarios from '@/router/router-constants/navigation-scenarios.js'; +import routerParams from '@/router/router-constants/router-params'; export default { name: 'coverage-statement', diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 45666547..c1964c7f 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -184,6 +184,7 @@ import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store'; import states from '@/constants/states'; import globalRules from '@/constants/global-rules'; +import routerParams from '@/router/router-constants/router-params'; // define validation rules defineRule('loss-date-required', required(errorMessages.LOSS_DATE_REQUIRED)); From a91d4ad43176048a65dc18ee2dd6987b07537d9a Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 13:01:35 -0400 Subject: [PATCH 093/674] Fixing parsing bug --- src/store/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index c582e318..a2bfbcd7 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -901,8 +901,8 @@ export const useMainStore = defineStore({ this.order.policy.deductible.repair = vehicle?.repairWaived ?? false ? 0 : vehicle.deductible; // TODO logic should be more complicated later on - this.order.originalDeductible = vehicle.deductible; - this.order.currentDeductible = vehicle.deductible; + this.order.originalDeductible = parseFloat(vehicle.deductible); + this.order.currentDeductible = parseFloat(vehicle.deductible); this.resetSupportingItemsState(); this.resetVapsState(); From 50313df9fcda1e9e14e9c74001aa51eeda648f11 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 13:13:20 -0400 Subject: [PATCH 094/674] fixing tests --- .../coverage-statement.spec.js | 37 ++++++++++++++++--- src/layouts/welcome-page/welcome-page.spec.js | 11 ++++-- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index 389444f5..857d1dcb 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -9,6 +9,7 @@ import navigationScenarios from '@/router/router-constants/navigation-scenarios. import { getRandomString, getRandomInt } from '@/helpers/data-generation.js'; import settleAllPromises from '@/helpers/layout-helper.js'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; +import routerParams from '@/router/router-constants/router-params'; jest.mock('@/helpers/layout-helper.js', () => jest.fn()); @@ -457,7 +458,11 @@ describe('coverageStatement.vue', () => { // Assert expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD, undefined); + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }); }); test('If Verified Deductible, navigate forward with CLICKED_FORWARD scenario', () => { // Arrange @@ -493,7 +498,11 @@ describe('coverageStatement.vue', () => { // Assert expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD, undefined); + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }); }); test('If Verified ITAC and selected Safelite, navigate forward with CLICKED_FORWARD_WITH_SAFELITE scenario', () => { // Arrange @@ -530,7 +539,11 @@ describe('coverageStatement.vue', () => { // Assert expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, undefined); + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }); }); test('If Verified ITAC, selected other shop, and TPA enabled, navigate forward w/ CLICKED_FORWARD_WITH_TPA_ENABLED', () => { // Arrange @@ -570,7 +583,11 @@ describe('coverageStatement.vue', () => { // Assert expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED, undefined); + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }); }); test('If Verified ITAC, selected other shop, and TPA disabled, navigate forward w/ CLICKED_FORWARD_WITH_TPA_DISABLED', () => { // Arrange @@ -610,7 +627,11 @@ describe('coverageStatement.vue', () => { // Assert expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED, undefined); + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }); }); test('If No Comp and selected Safelite, navigate forward with CLICKED_FORWARD scenario', () => { // Arrange @@ -636,7 +657,11 @@ describe('coverageStatement.vue', () => { // Assert expect(wrapper.vm.$router.navigate) - .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, undefined); + .toHaveBeenCalledWith( + navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }); }); }); describe('ADAS', () => { diff --git a/src/layouts/welcome-page/welcome-page.spec.js b/src/layouts/welcome-page/welcome-page.spec.js index ac4e132e..697451c8 100644 --- a/src/layouts/welcome-page/welcome-page.spec.js +++ b/src/layouts/welcome-page/welcome-page.spec.js @@ -10,6 +10,7 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js'; import applicationConfig from '@/constants/application-config'; import { useMainStore } from '@/store'; import navigationScenarios from '@/router/router-constants/navigation-scenarios'; +import routerParams from '@/router/router-constants/router-params'; // Mock our module for promises. jest.mock('@/helpers/layout-helper.js', () => jest.fn()); @@ -182,7 +183,7 @@ describe('navigation', () => { navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, undefined, {}, - {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }, mockvehicles ); }); @@ -208,7 +209,9 @@ describe('navigation', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, - undefined + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); }); test('if policy is not found, navigate to policy-holder-details page', async () => { @@ -228,7 +231,9 @@ describe('navigation', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith( navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED, - undefined + undefined, + {}, + { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); }); }); From 647eb4c9198d24e131d329cb6f7a93f5c6d71d56 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Wed, 6 Sep 2023 17:21:58 -0400 Subject: [PATCH 095/674] Remove bailout when no vehicle found --- src/layouts/vin-lookup/vin-lookup.vue | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/layouts/vin-lookup/vin-lookup.vue b/src/layouts/vin-lookup/vin-lookup.vue index bb91d977..67bd391f 100644 --- a/src/layouts/vin-lookup/vin-lookup.vue +++ b/src/layouts/vin-lookup/vin-lookup.vue @@ -112,8 +112,7 @@ export default { vehicleFromLookup: null, vin: this.getVinFromStore(), forwardButtonCarStyle: '', - vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0, - bailout: false + vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0 }; }, computed: { @@ -179,15 +178,8 @@ export default { // because the form itself actually passes its client-side validation. // SSR-189 Scenario #4. this.$refs.siteFooter.enableForwardAction(); - this.bailout = true; } - if (this.bailout) { - return this.$router.navigate( - this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT, - this.$route - ); - } // Add vin bcs the response from the service doesn't contain vin this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, { vin: this.vin }); } From b95124b428508013c9cf5438c02d0fbb6d24bbbf Mon Sep 17 00:00:00 2001 From: brydon1 Date: Thu, 7 Sep 2023 11:05:48 -0400 Subject: [PATCH 096/674] Removing bailout navigation test --- src/layouts/vin-lookup/vin-lookup.spec.js | 28 ----------------------- 1 file changed, 28 deletions(-) diff --git a/src/layouts/vin-lookup/vin-lookup.spec.js b/src/layouts/vin-lookup/vin-lookup.spec.js index 2e59dd23..d38cd24c 100644 --- a/src/layouts/vin-lookup/vin-lookup.spec.js +++ b/src/layouts/vin-lookup/vin-lookup.spec.js @@ -476,34 +476,6 @@ describe('vin-lookup.vue', () => { ); }); }); - - test('Selected vehicle VIN do not match vehicles (CarIDs) in our system then navigate forward to bailout page.', async () => { - // Arrange - const user = userEvent.setup(); - lookupVehicleByVin.mockResponse.data.error = true; - - jest.spyOn(VinLookupComponent.methods, lookupVehicleByVin.methodName) - .mockResolvedValue(lookupVehicleByVinError.mockResponse); - - mountOptions.data = () => ({ - needToLookupVehicle: true, - bailout: true, - vin: mockValidVin - }); - - const { container } = render(VinLookupComponent, mountOptions); - const continueButton = container.querySelector(continueButtonQuerySelector); - await user.click(continueButton); - - await flushPromises(); - await waitFor(() => { - expect(mockRouter.navigate).toHaveBeenCalledTimes(1); - expect(mockRouter.navigate).toHaveBeenCalledWith( - navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT, - mockRoute - ); - }); - }); }); }); }); From 2f384140e01c845a552ea3ae46b7129ae5a4c677 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 11 Sep 2023 10:56:15 -0400 Subject: [PATCH 097/674] remove console log --- src/layouts/policy-vehicles/policy-vehicles.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/policy-vehicles/policy-vehicles.vue b/src/layouts/policy-vehicles/policy-vehicles.vue index 5bc511f3..54f19ce9 100644 --- a/src/layouts/policy-vehicles/policy-vehicles.vue +++ b/src/layouts/policy-vehicles/policy-vehicles.vue @@ -152,7 +152,6 @@ export default { // save selected vehicle to the store this.mainStore.updateVehicle(vehicle.data); this.displayGeneric = false; - console.log(this.endorsementsForSelectedVehicle); } } } From 0f3a9a18d923131cdb3fa45973cce83a5d45c4a2 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 11 Sep 2023 10:56:33 -0400 Subject: [PATCH 098/674] fix importing of settleAllPromises --- src/layouts/endorsements-page/endorsements-page.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index 4277b73b..bbe57f4e 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -55,7 +55,7 @@ import questionChain from '@/digital-components/question-chain/question-chain.vu // Supporting files import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; -import { settleAllPromises } from '@/helpers/layout-helper'; +import settleAllPromises from '@/helpers/layout-helper'; import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import globalRules from '@/constants/global-rules.js'; From 60b7fe5d53c78f37475b5c8a5352950ef67436b7 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 11 Sep 2023 11:16:09 -0400 Subject: [PATCH 099/674] save endorsements answers to store --- src/store/index.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index a2bfbcd7..f213b2a8 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -58,7 +58,8 @@ const getDefaultState = () => ({ 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, - } + }, + endorsementQuestionAnswers: null, }, customer: { address: { @@ -817,6 +818,21 @@ export const useMainStore = defineStore({ 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); + } + + // Save new values + this.updateEndorsementQuestionAnswers(endorsementQuestionAnswersArray); + }, + saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) { const selectedGlassPassedInSorted = selectedGlassToReplace.slice().sort(); const isGlassToReplaceTheSame = this.order.damage.glassToReplace?.length === selectedGlassToReplace.length @@ -1014,6 +1030,10 @@ export const useMainStore = defineStore({ } }, + updateEndorsementQuestionAnswers(answersArray) { + this.order.policy.endorsementQuestionAnswers = answersArray; + }, + updateIsRepair(isRepair) { this.order.damage.isRepair = isRepair; }, From 3af5a3a204032dc8d1b0ed96638ca440f0349e4b Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 11 Sep 2023 14:46:38 -0400 Subject: [PATCH 100/674] create answer array and call method to save to store --- .../endorsements-page/endorsements-page.vue | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index bbe57f4e..7b7f1977 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -59,6 +59,7 @@ import settleAllPromises from '@/helpers/layout-helper'; import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import globalRules from '@/constants/global-rules.js'; +import { useMainStore } from '@/store'; export default { name: 'endorsements-page', @@ -117,7 +118,26 @@ export default { backButtonAction() { this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route); }, - forwardButtonAction() { + async forwardButtonAction() { + // manually creating the array for now, will revise once service returns questions + const questionAnswersArray = []; + + questionAnswersArray.push( + { + questionNum: 1, + questionText: this.schoolPropertyQuestionText, + selectedAnswer: this.schoolPropertyAnswer + }, + { + questionNum: 2, + questionText: this.parkingLotQuestionText, + selectedAnswer: this.parkingLotAnswer + } + ); + + // save answers to store as order.policy.endorsementQuestionAnswers + await this.mainStore.saveEndorsementQuestionAnswers(questionAnswersArray); + return this.navigateForward(); }, navigateForward() { From e1cf8e9d6317bd86707c937ca719d3de069d8952 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 11 Sep 2023 16:36:44 -0400 Subject: [PATCH 101/674] endorsements page styling WIP --- .../endorsements-page/endorsements-page.vue | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index 7b7f1977..510fda8b 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -7,11 +7,11 @@
- -
+ +
- + @backClicked="backButtonAction" + class="pt-5" />
@@ -149,22 +150,29 @@ export default { From 3ed110485cda95706fa0c16ba6bbccf6edec6d52 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Tue, 12 Sep 2023 11:08:05 -0400 Subject: [PATCH 102/674] Fixing adas link not working --- src/helpers/cms-content-helper.js | 8 +++++++- .../loading-modal/loading-modal.vue | 1 + .../coverage-statement/coverage-statement.vue | 16 +++++++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 12bd7043..473c7f2b 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -463,7 +463,13 @@ export function setupModalLinks(context) { for (const element of elements) { const target = element.getAttribute('modalTarget'); if (target) { - element.addEventListener('click', () => context.$refs[target].openModal()); + console.log('click event'); + console.log(target) + console.log(element) + element.addEventListener('click', () =>{ + console.log('hi'); + context.$refs[target].openModal() + }); } } }); diff --git a/src/iss-components/loading-modal/loading-modal.vue b/src/iss-components/loading-modal/loading-modal.vue index 02deed69..5c1cfb47 100644 --- a/src/iss-components/loading-modal/loading-modal.vue +++ b/src/iss-components/loading-modal/loading-modal.vue @@ -54,6 +54,7 @@ export default { if (evt.persisted) { setTimeout(() => { window.location.reload(); + console.log('reload'); }, 10); } }, diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index ccd03999..a1c3eec2 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -217,6 +217,8 @@ export default { return this.getHeaderTextFromCms('NextStepsWidget'); }, nextStepsBody() { + console.log('next steps body'); + return this.getBodyTextFromCms('NextStepsWidget')?.replaceAll('{custom:damage}', this.damageText); }, continueWithSchedulingBodyText() { @@ -314,10 +316,17 @@ export default { } else { this.$refs.siteFooter.updateButtonText('Continue'); } + }, + nextStepsBody(newValue, oldValue) { + console.log('watching next step'); + if (newValue !== oldValue){ + setupModalLinks(this); + } } }, async mounted() { this.$refs.loadingModal.showModal(); + console.log("mounted"); setupModalLinks(this); const vm = this; if (this.policyLookupSuccessful @@ -325,6 +334,7 @@ export default { && this.coveredAndServicePriceAboveOrEqualDeductible) { await useMainStore().registerClaim()?.catch(() => {}); } + //setupModalLinks(this); vm.$refs.loadingModal.hideModal(); }, methods: { @@ -374,9 +384,9 @@ export default { ); } }, - openModalAction(modalName) { - this.$refs[modalName.args].openModal(); - }, + // openModalAction(modalName) { + // this.$refs[modalName.args].openModal(); + // }, processIfStatements, getHeaderTextFromCms(cmsWidgetName) { const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); From 61583f5345c6f331fd16f41a8dd6abf0e958ee49 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Tue, 12 Sep 2023 11:09:42 -0400 Subject: [PATCH 103/674] Removing comments --- src/helpers/cms-content-helper.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 473c7f2b..12bd7043 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -463,13 +463,7 @@ export function setupModalLinks(context) { for (const element of elements) { const target = element.getAttribute('modalTarget'); if (target) { - console.log('click event'); - console.log(target) - console.log(element) - element.addEventListener('click', () =>{ - console.log('hi'); - context.$refs[target].openModal() - }); + element.addEventListener('click', () => context.$refs[target].openModal()); } } }); From d1d514adfd76c7c483dc7c5a34b8fec4a8f51b56 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Tue, 12 Sep 2023 11:11:07 -0400 Subject: [PATCH 104/674] Remove comment --- src/iss-components/loading-modal/loading-modal.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/iss-components/loading-modal/loading-modal.vue b/src/iss-components/loading-modal/loading-modal.vue index 5c1cfb47..02deed69 100644 --- a/src/iss-components/loading-modal/loading-modal.vue +++ b/src/iss-components/loading-modal/loading-modal.vue @@ -54,7 +54,6 @@ export default { if (evt.persisted) { setTimeout(() => { window.location.reload(); - console.log('reload'); }, 10); } }, From 3a70880471a49935b173576a9d050b38a2b84024 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Tue, 12 Sep 2023 11:32:24 -0400 Subject: [PATCH 105/674] Clean up --- src/layouts/coverage-statement/coverage-statement.vue | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index a1c3eec2..626187fd 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -318,7 +318,6 @@ export default { } }, nextStepsBody(newValue, oldValue) { - console.log('watching next step'); if (newValue !== oldValue){ setupModalLinks(this); } @@ -326,7 +325,6 @@ export default { }, async mounted() { this.$refs.loadingModal.showModal(); - console.log("mounted"); setupModalLinks(this); const vm = this; if (this.policyLookupSuccessful @@ -334,7 +332,6 @@ export default { && this.coveredAndServicePriceAboveOrEqualDeductible) { await useMainStore().registerClaim()?.catch(() => {}); } - //setupModalLinks(this); vm.$refs.loadingModal.hideModal(); }, methods: { @@ -384,9 +381,6 @@ export default { ); } }, - // openModalAction(modalName) { - // this.$refs[modalName.args].openModal(); - // }, processIfStatements, getHeaderTextFromCms(cmsWidgetName) { const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); From df94c4dda1d6781b8f865ffabd65be56a106eb8a Mon Sep 17 00:00:00 2001 From: brydon1 Date: Tue, 12 Sep 2023 11:34:27 -0400 Subject: [PATCH 106/674] Remove comment --- src/layouts/coverage-statement/coverage-statement.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 626187fd..ba9a854b 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -217,8 +217,6 @@ export default { return this.getHeaderTextFromCms('NextStepsWidget'); }, nextStepsBody() { - console.log('next steps body'); - return this.getBodyTextFromCms('NextStepsWidget')?.replaceAll('{custom:damage}', this.damageText); }, continueWithSchedulingBodyText() { From be499757b00396c556346174523524ee23941214 Mon Sep 17 00:00:00 2001 From: brydon1 Date: Tue, 12 Sep 2023 14:24:37 -0400 Subject: [PATCH 107/674] Updating only recal modal link when appropriate --- src/helpers/cms-content-helper.js | 14 ++++++++++++++ .../coverage-statement/coverage-statement.vue | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 12bd7043..861eacec 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -469,6 +469,20 @@ export function setupModalLinks(context) { }); } +/** + * + * @param context + * @param desiredTarget + */ +export function setupModalLink(context, desiredTarget) { + context.$nextTick(() => { + const element = document.querySelector(`[modalTarget=${desiredTarget}]`); + if (element) { + element.addEventListener('click', () => context.$refs[desiredTarget].openModal()); + } + }); +} + /** * * @param copy diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index ba9a854b..9cddedd6 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -112,7 +112,7 @@ import buttonQuestion from '@/digital-components/button-question/button-question import loadingModal from '@/iss-components/loading-modal/loading-modal.vue'; // Import Supporting Files -import { fetchCmsContentForPage, setupModalLinks, processIfStatements } from '@/helpers/cms-content-helper.js'; +import { fetchCmsContentForPage, setupModalLinks, setupModalLink, processIfStatements } from '@/helpers/cms-content-helper.js'; import settleAllPromises from '@/helpers/layout-helper.js'; import { getDamageString } from '@/helpers/damage-helper.js'; import { useMainStore } from '@/store/index.js'; @@ -317,7 +317,7 @@ export default { }, nextStepsBody(newValue, oldValue) { if (newValue !== oldValue){ - setupModalLinks(this); + setupModalLink(this, "RecalModal"); } } }, From edd5d4fc4ee284dbf52e3cbbc241572893f8a186 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 12 Sep 2023 14:58:34 -0400 Subject: [PATCH 108/674] linting --- .../endorsements-page/endorsements-page.vue | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index 510fda8b..de2ee33b 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -7,7 +7,9 @@
- +
+ @backClicked="backButtonAction" />
@@ -51,8 +53,6 @@ import siteHeader from '@/iss-components/site-header/site-header.vue'; import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue'; import buttonQuestion from '@/digital-components/button-question/button-question.vue'; -import questionsPageLayout from '@/iss-components/questions-page-layout/questions-page-layout.vue'; -import questionChain from '@/digital-components/question-chain/question-chain.vue'; // Supporting files import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; @@ -69,8 +69,6 @@ export default { siteSubHeader, siteFooter, buttonQuestion, - questionsPageLayout, - questionChain, // eslint-disable-next-line vue/no-reserved-component-names Form }, @@ -98,7 +96,7 @@ export default { rules: { selectionRequired: globalRules.OPTION_REQUIRED } - } + }; }, computed: { schoolPropertyQuestionText() { @@ -112,7 +110,7 @@ export default { }, parkingLotAnswersFromCms() { return this.getCmsContent('ParkingLotQuestion', 'Answers'); - }, + } }, methods: { @@ -122,9 +120,9 @@ export default { async forwardButtonAction() { // manually creating the array for now, will revise once service returns questions const questionAnswersArray = []; - + questionAnswersArray.push( - { + { questionNum: 1, questionText: this.schoolPropertyQuestionText, selectedAnswer: this.schoolPropertyAnswer @@ -135,15 +133,17 @@ export default { selectedAnswer: this.parkingLotAnswer } ); - + // save answers to store as order.policy.endorsementQuestionAnswers - await this.mainStore.saveEndorsementQuestionAnswers(questionAnswersArray); + await useMainStore().saveEndorsementQuestionAnswers(questionAnswersArray); return this.navigateForward(); }, navigateForward() { - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, - this.$route); + this.$router.navigate( + this.navigationScenarios.CLICKED_FORWARD, + this.$route + ); } } }; @@ -174,5 +174,4 @@ export default { margin-top: 1rem; } - From fc8ec1745df61698285ab91e1c558228de04f13b Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 12 Sep 2023 16:29:25 -0400 Subject: [PATCH 109/674] endorsements page unit tests so far --- .../endorsements-page.spec.js | 111 ++++++++++++++++++ .../endorsements-page/endorsements-page.vue | 10 +- 2 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 src/layouts/endorsements-page/endorsements-page.spec.js diff --git a/src/layouts/endorsements-page/endorsements-page.spec.js b/src/layouts/endorsements-page/endorsements-page.spec.js new file mode 100644 index 00000000..119bba29 --- /dev/null +++ b/src/layouts/endorsements-page/endorsements-page.spec.js @@ -0,0 +1,111 @@ +// Components +import endorsementsPage from '@/layouts/endorsements-page/endorsements-page.vue'; + +// Supporting Files +import { shallowMount } from '@vue/test-utils'; +import { getMountOptions } from '@/helpers/unit-test-helper.js'; +import navigationScenarios from '@/router/router-constants/navigation-scenarios'; +import { createTestingPinia } from '@pinia/testing'; +import { getRandomString, getRandomInt } from '@/helpers/data-generation.js'; +import { useMainStore } from '@/store'; + +// import { useMainStore } from '@/store/index.js'; + +describe('endorsementsPage.vue', () => { + describe('Rendering', () => { + test('Should render site header', () => { + // Arrange + const wrapper = shallowMount(endorsementsPage, getMountOptions()); + + // Act + const siteHeader = wrapper.findComponent({ ref: 'siteHeader' }); + + // Assert + expect(siteHeader.exists()).toBe(true); + }); + test('Should render site subheader', () => { + // Arrange + const wrapper = shallowMount(endorsementsPage, getMountOptions()); + + // Act + const siteSubHeader = wrapper.findComponent({ ref: 'siteSubHeader' }); + + // Assert + expect(siteSubHeader.exists()).toBe(true); + }); + test('Should render buttonQuestion component', () => { + // Arrange + const wrapper = shallowMount(endorsementsPage, getMountOptions()); + + // Act + const buttonQuestion = wrapper.findComponent({ ref: 'endorsementQuestion' }); + + // Assert + expect(buttonQuestion.exists()).toBe(true); + }); + test('Should render site footer', () => { + // Arrange + const wrapper = shallowMount(endorsementsPage, getMountOptions()); + + // Act + const siteFooter = wrapper.findComponent({ ref: 'siteFooter' }); + + // Assert + expect(siteFooter.exists()).toBe(true); + }); + }); + describe('Navigation', () => { + test('Back button clicked triggers navigation', () => { + // Arrange + const wrapper = shallowMount(endorsementsPage, getMountOptions({ + router: { + navigate: jest.fn() + } + })); + + // Act + wrapper.vm.backButtonAction(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); + expect(wrapper.vm.$router.navigate) + .toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK, undefined); + }); + test('Forward button clicked triggers navigation', () => { + // Arrange + const wrapper = shallowMount(endorsementsPage, getMountOptions({ + router: { + navigate: jest.fn() + } + })); + + // Act + wrapper.vm.forwardButtonAction(); + wrapper.vm.navigateForward(); + + // Assert + expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); + expect(wrapper.vm.$router.navigate) + .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD, undefined); + }); + // *TO DO: once service is ready, revise this test to ensure data is saved to the store + test('Forward button clicked saves endorsement question answers', () => { + // Arrange + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + }, + global: { + plugins: [createTestingPinia()] + } + }); + const wrapper = shallowMount(endorsementsPage, mountOptions); + + // Act + wrapper.vm.forwardButtonAction(); + + // Assert + expect(useMainStore().saveEndorsementQuestionAnswers).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/layouts/endorsements-page/endorsements-page.vue b/src/layouts/endorsements-page/endorsements-page.vue index de2ee33b..4b779dca 100644 --- a/src/layouts/endorsements-page/endorsements-page.vue +++ b/src/layouts/endorsements-page/endorsements-page.vue @@ -6,12 +6,16 @@ @invalidSubmit="onInvalidSubmit">
- +
@@ -135,7 +139,7 @@ export default { ); // save answers to store as order.policy.endorsementQuestionAnswers - await useMainStore().saveEndorsementQuestionAnswers(questionAnswersArray); + useMainStore().saveEndorsementQuestionAnswers(questionAnswersArray); return this.navigateForward(); }, From c90ef8b7c2b340da72e1a90c55c235c6c25cc153 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 12 Sep 2023 17:02:57 -0400 Subject: [PATCH 110/674] linting --- .../endorsements-page/endorsements-page.spec.js | 1 - src/layouts/policy-vehicles/policy-vehicles.vue | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/layouts/endorsements-page/endorsements-page.spec.js b/src/layouts/endorsements-page/endorsements-page.spec.js index 119bba29..a7eaa593 100644 --- a/src/layouts/endorsements-page/endorsements-page.spec.js +++ b/src/layouts/endorsements-page/endorsements-page.spec.js @@ -6,7 +6,6 @@ import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; import navigationScenarios from '@/router/router-constants/navigation-scenarios'; import { createTestingPinia } from '@pinia/testing'; -import { getRandomString, getRandomInt } from '@/helpers/data-generation.js'; import { useMainStore } from '@/store'; // import { useMainStore } from '@/store/index.js'; diff --git a/src/layouts/policy-vehicles/policy-vehicles.vue b/src/layouts/policy-vehicles/policy-vehicles.vue index 54f19ce9..5287be82 100644 --- a/src/layouts/policy-vehicles/policy-vehicles.vue +++ b/src/layouts/policy-vehicles/policy-vehicles.vue @@ -200,12 +200,15 @@ export default { this.navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE, this.$route, {}, - {}); - } else if (!!this.endorsementsForSelectedVehicle) { - this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS, + {} + ); + } else if (this.endorsementsForSelectedVehicle) { + this.$router.navigate( + this.navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS, this.$route, {}, - {}); + {} + ); } else { this.$router.navigate( this.navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE, From 17ecf1ebec40ff374b13053b1757864fba8ff043 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 30 Aug 2023 15:54:37 -0400 Subject: [PATCH 111/674] commit before stash --- .../service-location/service-location.vue | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 252741c1..b1fd6449 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -5,52 +5,45 @@ @submit="onSubmit" @invalidSubmit="onInvalidSubmit">
-
- - -
-
-
-
-
- - - -
- -
-
-
-
-
-
+ + +
+ + + + +
@@ -164,8 +157,18 @@ export default { } return this.isGlassServiceableMobile; }, + isServiceableInshop() { + if (this.isRecalibrationServiceableInshop !== null) { + return this.isGlassServiceableInshop && this.isRecalibrationServiceableInshop; + } + + return this.isGlassServiceableInshop; + }, displayMilitaryZipAlert() { return this.zipContainsMilitaryBase && this.isServiceableMobile; + }, + displayServiceableMobileOnly() { + return this.isServiceableMobile && !this.isServiceableInshop; } }, methods: { @@ -214,18 +217,16 @@ export default { diff --git a/src/helpers/cms-content-helper.js b/src/helpers/cms-content-helper.js index 861eacec..5120c4db 100644 --- a/src/helpers/cms-content-helper.js +++ b/src/helpers/cms-content-helper.js @@ -12,9 +12,11 @@ function processWidgetItemForReplacement(widgetModel, key) { // If we have a string, and it needs to be replaced. if (typeof widgetModel[key] === 'string') { if (widgetModel[key].includes('{if:')) { - widgetModel[key] = processIfStatements(widgetModel[key], + widgetModel[key] = processIfStatements( + widgetModel[key], dynamicStrings.GLOBAL_STATE, - getStoreValueFromString); + getStoreValueFromString + ); } if (widgetModel[key].includes(dynamicStrings.MODAL_LINK)) { @@ -158,14 +160,16 @@ export function fetchCmsContentForPage(issPage) { // Else get the client override page. const pageName = `${issPage}_${clientName.toLowerCase().replace(/ /g, '')}`; - return store.getPageData(pageName).then((clientResponse) => - // Process the client override if it exists. - processPageData(baseResponse, clientResponse), - (error) => { - console.error(error); - // Process the just the base if no client override exists. - return processPageData(baseResponse, null); - }); + return store.getPageData(pageName).then( + (clientResponse) => + // Process the client override if it exists. + processPageData(baseResponse, clientResponse), + (error) => { + console.error(error); + // Process the just the base if no client override exists. + return processPageData(baseResponse, null); + } + ); }) ); } @@ -179,8 +183,10 @@ function mapStringToModal(str) { let linkToReplace = str.substring(startIndex, str.length); linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1); - const params = linkToReplace.substring(dynamicStrings.MODAL_LINK.length + 2, - linkToReplace.length - 1); + const params = linkToReplace.substring( + dynamicStrings.MODAL_LINK.length + 2, + linkToReplace.length - 1 + ); const splitParams = params.split(','); const bodyText = `${splitParams[1]}`; @@ -202,8 +208,10 @@ function mapStringToLink(str) { let linkToReplace = str.substring(startIndex, str.length); linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1); - const params = linkToReplace.substring(dynamicStrings.EXTERNAL_LINK.length + 2, - linkToReplace.length - 1); + const params = linkToReplace.substring( + dynamicStrings.EXTERNAL_LINK.length + 2, + linkToReplace.length - 1 + ); const splitParams = params.split(','); const bodyText = `${splitParams[1]}`; @@ -291,13 +299,17 @@ export function processIfStatements(str, ifConditionKeyword, replacePlaceholderC } const ifStatementRegexExpression = getIfStatementRegexExpression(); const ifStatementRegexMatches = [...str.matchAll(ifStatementRegexExpression)]; - const completeIfStatementArray = getAndFlagFirstNonNestedIfStatementWithKeyword(ifStatementRegexMatches, - ifConditionKeyword); + const completeIfStatementArray = getAndFlagFirstNonNestedIfStatementWithKeyword( + ifStatementRegexMatches, + ifConditionKeyword + ); executeIfStatementAndSetProcessedStrings(completeIfStatementArray, replacePlaceholderCallback); const reconstructedPostProcessedString = joinProcessedRegexArray(ifStatementRegexMatches); - return processIfStatements(reconstructedPostProcessedString, + return processIfStatements( + reconstructedPostProcessedString, ifConditionKeyword, - replacePlaceholderCallback); + replacePlaceholderCallback + ); } /** @@ -419,26 +431,28 @@ function getIfStatementRegexExpression() { // {if:...} or {else} or {end} const anyLogicOperatorNonCapture = '(?:{(?:end|else|if:.*?)})'; // NOTE: ? syntax stores the captured match like so: match.groups.variableName - const matchStartOfString - = '(?^.+?)' // Match and Capture all characters (lazy), cannot be empty + const matchStartOfString = + '(?^.+?)' // Match and Capture all characters (lazy), cannot be empty + '(?=(?:{if))'; // Looks ahead but does not capture {if - const matchIfOperator - = '(?{if:)' // Match & Capture {if: + const matchIfOperator = + '(?{if:)' // Match & Capture {if: + '(?.*?):' // Match all chars up to and including next ':' - Capture all chars up to ':' + '(?.*?)}' // Match all chars up to and including next '}' - Capture all chars up to '}' + '(?.*?)' // Match and Capture all characters (lazy), can be empty + `(?=${anyLogicOperatorNonCapture})`; // Looks ahead but does not capture the next logic operator - const matchElseOperator - = '(?{else})' // Match & Capture {else} + const matchElseOperator = + '(?{else})' // Match & Capture {else} + '(?.*?)' // Match & Capture all characters (lazy), can be empty + `(?=${anyLogicOperatorNonCapture})`; // Looks ahead but does not capture the next logic operator - const matchEndOperator - = '(?{end})' // Match & Capture {end} + const matchEndOperator = + '(?{end})' // Match & Capture {end} + '(?.*?)' // Match & Capture all characters (lazy), can be empty + `(?=${anyLogicOperatorNonCapture}|$)`; // Looks ahead but does not capture the next logic operator // Combine all matching patterns, separated by 'or' pipes - return new RegExp(`${matchStartOfString}|${matchIfOperator}|${matchElseOperator}|${matchEndOperator}`, - 'g'); + return new RegExp( + `${matchStartOfString}|${matchIfOperator}|${matchElseOperator}|${matchEndOperator}`, + 'g' + ); } /// /////////////////////////////////////// @@ -501,6 +515,16 @@ export function splitCopyOnCMSPlaceHolder(copy) { return copy.split(/{(.*?)}/g); } +export function getExternalLink(copy) { + const url = copy.split(':')[1].split(',')[0]; + if (url.includes('https-')) { + const prefixAdded = url.replace('https-', 'https://'); + return prefixAdded; + } + + return '#!'; +} + /** * Returns string2 of input following this pattern: {string1:string2,string3} * @param copy diff --git a/src/helpers/object-helper.js b/src/helpers/object-helper.js new file mode 100644 index 00000000..5c1cafd6 --- /dev/null +++ b/src/helpers/object-helper.js @@ -0,0 +1,80 @@ +// For nested objects, spread operator only creates new references to the top level fields, +// the remaining nested fields actually reference the original object which can introduce problems. + +// The purpose of this method is to deep clone the data in an object recursively, this is useful +// for cloning modelValues to internal models when regular two-way binding is not an option. +// See: mobile-location-modal-questions.vue + +// Creates a deep clone of an object. Clones primitives, arrays and objects, excluding class instances. +// https://www.30secondsofcode.org/js/s/deep-clone +export function deepClone(object) { + if (object === null) { + return null; + } + + const clone = { ...object }; + // eslint-disable-next-line no-return-assign + Object.keys(clone).forEach((key) => + (clone[key] = typeof object[key] === 'object' ? deepClone(object[key]) : object[key])); + + if (Array.isArray(object)) { + clone.length = object.length; + return Array.from(clone); + } + + return clone; +} + +// The purpose of this method is to check for array or object equality recursively to determine if two complex objects are equal. +// This is only a comparison of data, not functions. +export function deepEqual(obj1, obj2) { + if (typeof obj1 !== typeof obj2) { + return false; + } + + if (obj1 === null || obj2 === null) { + return obj1 === obj2; + } + + if (Array.isArray(obj1) && Array.isArray(obj2)) { + if (obj1.length !== obj2.length) { + return false; + } + + const sorted1 = obj1.slice().sort(); + const sorted2 = obj2.slice().sort(); + + for (let i = 0; i < sorted1.length; i++) { + if (!deepEqual(sorted1[i], sorted2[i])) { + return false; + } + } + + return true; + } + + if (typeof obj1 === 'object' && typeof obj2 === 'object') { + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + if (keys1.length !== keys2.length) { + return false; + } + + const sortedKeys1 = keys1.sort(); + const sortedKeys2 = keys2.sort(); + + for (let i = 0; i < sortedKeys1.length; i++) { + const key1 = sortedKeys1[i]; + const key2 = sortedKeys2[i]; + + if (key1 !== key2 || !deepEqual(obj1[key1], obj2[key2])) { + return false; + } + } + + return true; + } + + return obj1 === obj2; +} diff --git a/src/helpers/service-location-helper.js b/src/helpers/service-location-helper.js index 242752d3..a8ac5503 100644 --- a/src/helpers/service-location-helper.js +++ b/src/helpers/service-location-helper.js @@ -1,16 +1,5 @@ import { useMainStore } from '@/store'; -export async function getServiceabilityDetails(serviceZipCode, lineItems) { - const serviceabilityDetails = await useMainStore().getServiceabilityDetails( - { - serviceZipCode, - lineItems - }, - false - ); - return Promise.resolve(serviceabilityDetails); -} - export async function getZipCodeData(zipCode) { const serviceZipValidationResponse = await useMainStore().validateZip({ zip: zipCode }); @@ -22,3 +11,57 @@ export async function getZipCodeData(zipCode) { zipCodeCtu: serviceZipValidationResponse.data.zipCodeCtu }; } + +export async function getPricedMobileFeePart(serviceZipCode) { + if (!serviceZipCode) { + return Promise.resolve(null); + } + const zipCodeData = await getZipCodeData(serviceZipCode); + + // Get the Mobile Fee Part + const mobileFeePart = await useMainStore().getMobileFeePart(); + + // Get the Mobile Fee Part Price + const pricingResults = await useMainStore() + .priceOrderItemsAndSaveServerData([mobileFeePart.data], serviceZipCode, zipCodeData.zipCodeCtu); + + return Promise.resolve(pricingResults[0]); +} + +export async function getServiceabilityDetails(serviceZipCode, lineItems) { + const serviceabilityDetails = await useMainStore().getServiceabilityDetails( + { + serviceZipCode, + lineItems + }, + false + ); + return Promise.resolve(serviceabilityDetails); +} + +export async function getAvailabilityRating( + startDate, + endDate, + shopAppointmentType, + providerNumber +) { + // For a given shop provider number and date range, get the appointment time slots available + const shopTimeSlots = await useMainStore().getShopTimeSlots( + { + providerNumber, + startDate, + endDate, + shopAppointmentType + }, + false + ); + + const numberOfDaysToEvaluate = 2; + const isGoodAvailability = + shopTimeSlots.data.days.filter((x) => x.timeSlots.length > 0).length + >= numberOfDaysToEvaluate; + + const shopStatus = isGoodAvailability ? 'high' : 'low'; + + return Promise.resolve(shopStatus); +} diff --git a/src/iss-components/site-footer/site-footer.vue b/src/iss-components/site-footer/site-footer.vue index f83d8372..2c4a4cb0 100644 --- a/src/iss-components/site-footer/site-footer.vue +++ b/src/iss-components/site-footer/site-footer.vue @@ -2,7 +2,7 @@
+ class="footer container-fluid g-5 my-5 px-0">
{ vm.setCmsContent(resultMap.cmsContent); + vm.setSupportingItems(resultMap.supportingItems); // eslint-disable-next-line no-param-reassign vm.availableLineItems = pricingResults; }); @@ -188,7 +201,8 @@ export default { ], rules: { selectionRequired: globalRules.OPTION_REQUIRED - } + }, + supportingItems: null }; }, computed: { @@ -341,6 +355,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { + this.mainStore.saveSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -349,6 +364,7 @@ export default { ); } else if (this.verifiedITAC || this.verifiedNoComp) { if (this.selectedProvider === 'Safelite') { + this.mainStore.saveSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route, @@ -437,6 +453,9 @@ export default { }, getITACCostSavings(vehicleDeductible, totalServicePrice) { return vehicleDeductible - totalServicePrice; + }, + setSupportingItems(newSupportingItems) { + this.supportingItems = newSupportingItems; } } }; diff --git a/src/layouts/service-location/appointment-type-question/appointment-type-question.vue b/src/layouts/service-location/appointment-type-question/appointment-type-question.vue new file mode 100644 index 00000000..25e7a529 --- /dev/null +++ b/src/layouts/service-location/appointment-type-question/appointment-type-question.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue new file mode 100644 index 00000000..ddd6998b --- /dev/null +++ b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue @@ -0,0 +1,322 @@ + + + + + diff --git a/src/layouts/service-location/mobile-location-modal-questions/vehicle-protected-question/vehicle-protected-question.vue b/src/layouts/service-location/mobile-location-modal-questions/vehicle-protected-question/vehicle-protected-question.vue new file mode 100644 index 00000000..af67995e --- /dev/null +++ b/src/layouts/service-location/mobile-location-modal-questions/vehicle-protected-question/vehicle-protected-question.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index b1fd6449..ebbc1334 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -28,15 +28,58 @@ class="my-5" cmsWidgetName="AlertMobileOnlyWidget" alertClass="alert-warning" /> - + + + + :isServiceableMobile="isServiceableMobile" + :isServiceableInshop="isServiceableInshop" + :isDisplayed="isAppointmentTypeDisplayed" + groupName="appointmentTypeQuestion" + cmsWidgetName="AppointmentTypeQuestionWidget" + validationRules="option-required" /> + + + { + if ( + value.addressQuestions.streetAddress === '' + || value.addressQuestions.city === '' + || value.addressQuestions.state === '' + || value.addressQuestions.zipCode === '' + || value.isVehicleProtected == null + ) { + return errorMessages.MOBILE_LOCATION_REQUIRED; + } + return true; +}); defineRule('selection-required', required(errorMessages.OPTION_REQUIRED)); export default { name: 'service-location', components: { + alert, + appointmentTypeQuestion, + contentGroupModal, + mobileLocationModalQuestions, siteFooter, siteHeader, siteSubHeader, - buttonQuestion, // eslint-disable-next-line vue/no-reserved-component-names Form, serviceZipModalQuestion, - alert + shopQuestion }, mixins: [baseFormMixin], async beforeRouteEnter(to, from, next) { @@ -89,7 +150,9 @@ export default { const serviceZipCode = useMainStore().order.customer.address.zipCode; const zipCodeData = getZipCodeData(serviceZipCode); + const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode); const serviceabilityDetailsPromise = getServiceabilityDetails(serviceZipCode); + const shopQuestionInitialDataPromise = shopQuestion.methods.loadInitialData(serviceZipCode); // Settle promises and get results const promiseResultMap = [ @@ -97,10 +160,18 @@ export default { resultKey: 'cmsContent', promise: cmsContentPromise }, + { + resultKey: 'mobileFeePart', + promise: mobileFeePartPromise + }, { resultKey: 'serviceabilityDetails', promise: serviceabilityDetailsPromise }, + { + resultKey: 'shopQuestionInitialData', + promise: shopQuestionInitialDataPromise + }, { resultKey: 'zipCodeData', promise: zipCodeData @@ -108,10 +179,10 @@ export default { ]; const resultMap = await settleAllPromises(promiseResultMap); - next((vm) => { vm.setCmsContent(resultMap.cmsContent); - vm.setData(resultMap.zipCodeData, resultMap.serviceabilityDetails); + vm.setData(resultMap.zipCodeData, resultMap.serviceabilityDetails, resultMap.mobileFeePart); + vm.$refs.shopQuestion.initializeComponent(resultMap.shopQuestionInitialData); }); }, setup() { @@ -120,13 +191,21 @@ export default { }, data() { return { - zipCode: this.mainStore.order.customer.address.zipCode, - state: this.mainStore.order.customer.address.state, - isServiceZipServiceable: null, + streetAddress: this.getServiceAddressFromStore(), + apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(), + city: this.getServiceCityFromStore(), + state: this.getServiceStateFromStore(), + zipCode: this.getServiceZipCodeFromStore(), + isVehicleProtected: this.getIsVehicleProtectedFromStore(), + isGlassServiceableInshop: null, + isRecalibrationServiceableInshop: null, isGlassServiceableMobile: null, isRecalibrationServiceableMobile: null, - selectedAppointmentType: '', - zipContainsMilitaryBase: false + selectedAppointmentType: this.getSelectedAppointmentType(), + selectedProvider: this.getSelectedProvider(), + mobileFeePart: null, + zipContainsMilitaryBase: false, + zipCodeCtu: null }; }, computed: { @@ -139,18 +218,54 @@ export default { serviceZipCodeQuestion: { get() { return { - zipCode: this.zipCode, - state: this.state + state: this.state, + zipCode: this.zipCode }; }, set(newValue) { - this.zipCode = newValue.zipCode; - this.state = newValue.state; + if (newValue.zipCode !== this.zipCode) { + this.resetMobileLocation(); + this.selectedAppointmentType = null; + this.selectedProvider = null; + } - // TODO: review - this seems like it should be awaited. + this.state = newValue.state; + this.zipCode = newValue.zipCode; + + // eslint-disable-next-line vue/valid-next-tick this.$nextTick(); } }, + mobileLocationQuestions: { + get() { + return { + addressQuestions: { + streetAddress: this.streetAddress, + apartmentNumberOrBusinessName: this.apartmentNumberOrBusinessName, + city: this.city, + state: this.state, + zipCode: this.zipCode + }, + isVehicleProtected: this.isVehicleProtected + }; + }, + set(newValue) { + this.streetAddress = newValue.addressQuestions.streetAddress; + this.apartmentNumberOrBusinessName = + newValue.addressQuestions.apartmentNumberOrBusinessName; + this.city = newValue.addressQuestions.city; + this.state = newValue.addressQuestions.state; + this.zipCode = newValue.addressQuestions.zipCode; + this.isVehicleProtected = newValue.isVehicleProtected; + + if (newValue.zipCode !== this.zipCode) { + if (!this.selectedAppointmentType === 'Mobile') { + this.selectedAppointmentType = null; + } + this.selectedProvider = null; + } + } + }, isServiceableMobile() { if (this.isRecalibrationServiceableMobile !== null) { return this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile; @@ -164,9 +279,39 @@ export default { return this.isGlassServiceableInshop; }, + isShopQuestionDisplayed() { + return ( + this.selectedAppointmentType === 'Inshop' + || this.selectedAppointmentType === 'Dropoff' + ); + }, + isAppointmentTypeDisplayed() { + return true; // this.zipCode && !this.displayNoShopsAlert; + }, + requiresInshopRecalibration() { + // Specifically check for isRecalibrationServiceableMobile === false, not null or true. + return ( + this.isServiceableInshop + && this.isGlassServiceableMobile + && this.isRecalibrationServiceableMobile === false + ); + }, displayMilitaryZipAlert() { return this.zipContainsMilitaryBase && this.isServiceableMobile; }, + displayNoShopsAlert() { + return !this.isServiceableInshop && !this.isServiceableMobile; + }, + displayRecalibrationWarning() { + return this.requiresInshopRecalibration; + }, + displayServiceableInshopOnly() { + return ( + !this.displayRecalibrationWarning + && this.isServiceableInshop + && !this.isServiceableMobile + ); + }, displayServiceableMobileOnly() { return this.isServiceableMobile && !this.isServiceableInshop; } @@ -185,32 +330,93 @@ export default { this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route); }, async forwardButtonAction() { - // validate and save data here + useMainStore().saveServiceLocation({ + address: this.streetAddress, + address2: this.apartmentNumberOrBusinessName, + city: this.city, + state: this.state, + zipCode: this.zipCode, + zipCodeCtu: this.zipCodeCtu, + appointmentType: this.selectedAppointmentType, + isVehicleProtected: this.isVehicleProtected, + provider: { + providerNumber: this.selectedProvider?.providerNumber, + address: { + streetAddress: this.selectedProvider?.address?.streetAddress, + city: this.selectedProvider?.address?.city, + state: this.selectedProvider?.address?.state, + zipCode: this.selectedProvider?.address?.zipCode, + zipCodeCtu: this.selectedProvider?.address?.zipCodeCtu + } + } + }); + this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route); }, + openModalAction(modalName) { + this.$refs[modalName].openModal(); + }, resetDependentState() { }, - setData(zipCodeData, serviceabilityDetails) { + getServiceAddressFromStore() { + return useMainStore().order.serviceLocation.address; + }, + getServiceAddress2FromStore() { + return useMainStore().order.serviceLocation.address2; + }, + getServiceCityFromStore() { + return useMainStore().order.serviceLocation.city; + }, + getServiceStateFromStore() { + return useMainStore().order.serviceLocation.state; + }, + getServiceZipCodeFromStore() { + return useMainStore().order.customer.address.zipCode; + // return useMainStore().order.serviceLocation.zipCode; + }, + getIsVehicleProtectedFromStore() { + return useMainStore().order.serviceLocation.isVehicleProtected; + }, + getSelectedAppointmentType() { + return useMainStore().order.serviceLocation.appointmentType; + }, + getSelectedProvider() { + return useMainStore().order.serviceLocation.provider; + }, + setData(zipCodeData, serviceabilityDetails, mobileFeePart) { if (zipCodeData) { this.zipContainsMilitaryBase = zipCodeData.containsMilitaryBase; } + if (serviceabilityDetails) { this.setServiceabilityDetails(serviceabilityDetails); } + + if (mobileFeePart) { + this.mobileFeePart = mobileFeePart; + } }, setContainsMilitaryBase(val) { if (this.zipContainsMilitaryBase !== val) { this.zipContainsMilitaryBase = val; } }, + setMobileFeePart(mobileFeePart) { + this.mobileFeePart = mobileFeePart; + }, + resetMobileLocation() { + this.streetAddress = ''; + this.apartmentNumberOrBusinessName = ''; + this.city = ''; + + this.isVehicleProtected = null; + }, setServiceabilityDetails(serviceabilityDetails) { this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop; - this.isRecalibrationServiceableInshop = - serviceabilityDetails.isRecalibrationServiceableInshop; + this.isRecalibrationServiceableInshop = serviceabilityDetails.isRecalibrationServiceableInshop; this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile; - this.isRecalibrationServiceableMobile = - serviceabilityDetails.isRecalibrationServiceableMobile; + this.isRecalibrationServiceableMobile = serviceabilityDetails.isRecalibrationServiceableMobile; } } }; diff --git a/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue b/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue new file mode 100644 index 00000000..c34d67c9 --- /dev/null +++ b/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue @@ -0,0 +1,205 @@ + + + + + diff --git a/src/layouts/service-location/shop-question/shop-question.vue b/src/layouts/service-location/shop-question/shop-question.vue new file mode 100644 index 00000000..2edeba6c --- /dev/null +++ b/src/layouts/service-location/shop-question/shop-question.vue @@ -0,0 +1,284 @@ + + + + + diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js index b9636fcd..ff9655ab 100644 --- a/src/mixins/base-mixin.js +++ b/src/mixins/base-mixin.js @@ -25,6 +25,14 @@ export default { }, savePageDataToStore(page, data) { useMainStore().updatePageData({ page, data }); + }, + scrollToPageTop() { + const container = document.getElementsByClassName('page-container-grouped-styles')[0]; + container.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); + }, + scrollToPageBottom() { + const container = document.getElementsByClassName('page-container-grouped-styles')[0]; + container.scrollTo({ top: container.scrollHeight, left: 0, behavior: 'smooth' }); } }, computed: { diff --git a/src/store/index.js b/src/store/index.js index a2bfbcd7..baed5200 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -11,6 +11,7 @@ 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 { PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants'; const storeId = 'main'; @@ -75,10 +76,24 @@ const getDefaultState = () => ({ }, serviceLocation: { address: null, + address2: null, city: null, state: null, zipCode: null, - zipCodeCtu: null + zipCodeCtu: null, + appointmentType: null, + isVehicleProtected: null, + provider: { + providerNumber: null, + address: { + streetAddress: null, + city: null, + state: null, + zipCode: null, + zipCodeCtu: null + } + }, + techNotes: null }, lineItems: { glassParts: null, @@ -91,7 +106,8 @@ const getDefaultState = () => ({ insuranceCoverage: { isVerified: false, coverageStatus: coverageStatuses.PENDING - } + }, + parentAccountNumber: 0 }, contactInfo: { firstName: null, @@ -106,7 +122,8 @@ const getDefaultState = () => ({ startTime: null, endTime: null, routeCode: null, - jobMaxMinutes: null + jobMaxMinutes: null, + jobMinMinutes: null }, referralNumber: null, referralDate: null, @@ -562,6 +579,63 @@ export const useMainStore = defineStore({ } }); }, + + 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, + 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 @@ -593,6 +667,16 @@ export const useMainStore = defineStore({ }); }, + 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}` + }); + }, + async getSupportingItems() { const glassPartsArray = this.order.lineItems.glassParts ?? []; const { carId } = this.order.vehicle; @@ -649,9 +733,20 @@ export const useMainStore = defineStore({ 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.glassParts.map((glassPart) => ({ - partNumber: glassPart.partNumber + const lineItemsWithOnlyPartNumbers = this.order.lineItems.supportingItems.map((lineItem) => ({ + partNumber: lineItem.partNumber })); const lineItems = buildQueryStringParameterFromArrayOfComplexObjects(lineItemsWithOnlyPartNumbers, 'lineItems'); @@ -691,7 +786,7 @@ export const useMainStore = defineStore({ }); }, - setSaveSessionInfo(response){ + setSaveSessionInfo(response) { this.order.referralNumber = response.referralNumber; this.order.referralSequenceNumber = response.referralSequenceNumber; this.order.referralDate = response.referralDate; @@ -809,11 +904,11 @@ export const useMainStore = defineStore({ }); }, - setSaveSessionPromise(promise){ + setSaveSessionPromise(promise) { this.applicationUser.saveSessionPromise = promise; }, - clearSaveSessionPromise(){ + clearSaveSessionPromise() { this.applicationUser.saveSessionPromise = null; }, @@ -853,11 +948,25 @@ export const useMainStore = defineStore({ }, updateServiceLocation(serviceLocationInfo) { - this.order.serviceLocation.address = serviceLocationInfo.address; - this.order.serviceLocation.city = serviceLocationInfo.city; - this.order.serviceLocation.state = serviceLocationInfo.state; - this.order.serviceLocation.zipCode = serviceLocationInfo.zipCode; - this.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu; + state.order.serviceLocation.address = serviceLocationInfo.address; + state.order.serviceLocation.address2 = serviceLocationInfo.address2; + state.order.serviceLocation.city = serviceLocationInfo.city; + state.order.serviceLocation.state = serviceLocationInfo.state; + state.order.serviceLocation.zipCode = serviceLocationInfo.zipCode; + state.order.serviceLocation.zipCodeCtu = serviceLocationInfo.zipCodeCtu; + state.order.serviceLocation.appointmentType = serviceLocationInfo.appointmentType; + state.order.serviceLocation.isVehicleProtected = serviceLocationInfo.isVehicleProtected; + + state.order.serviceLocation.provider = { + providerNumber: serviceLocationInfo.provider?.providerNumber, + address: { + streetAddress: serviceLocationInfo.provider?.address?.streetAddress, + city: serviceLocationInfo.provider?.address?.city, + state: serviceLocationInfo.provider?.address?.state, + zipCode: serviceLocationInfo.provider?.address?.zipCode, + zipCodeCtu: serviceLocationInfo.provider?.address?.zipCodeCtu + } + }; }, resetRegistrationState() { @@ -869,6 +978,28 @@ export const useMainStore = defineStore({ this.order.vehicle.registration.firstName = null; this.order.vehicle.registration.lastName = null; }, + 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; + }, updateSupportingItems(partsData) { this.order.lineItems.supportingItems = partsData; @@ -935,7 +1066,23 @@ export const useMainStore = defineStore({ 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; }, @@ -1128,6 +1275,47 @@ export const useMainStore = defineStore({ 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 }); }, @@ -1319,6 +1507,20 @@ export const useMainStore = defineStore({ }, saveServiceLocation(serviceLocationInfo) { + console.log(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); }, @@ -1529,6 +1731,20 @@ function getLineItemQueryStringForPricing(lineItems) { }).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++) { @@ -1539,3 +1755,27 @@ function buildQueryStringParameterFromArrayOfComplexObjects(arrayOfObjects, para // Remove trailing & return queryStringParameter.slice(0, -1); } + +function convertGlassPieceToBackEndCompatibleFormat(glassPieces) { + return glassPieces.map((glassPiece) => ({ + location: glassPiece.glassLocation, + name: glassPiece.glassName + })); +} + +function providersEqual(providerA, providerB) { + console.log(providerA); + console.log(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(',')}`; +} diff --git a/src/styles/common-styles.scss b/src/styles/common-styles.scss index 80654ed8..72d1c042 100644 --- a/src/styles/common-styles.scss +++ b/src/styles/common-styles.scss @@ -4,28 +4,35 @@ body { font-size: 16px; background-color: #fff; color: #4D5151; + .container-fluid { max-width: 576px; //Remove once desktop app is complete + &.container-shadow { - box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.15); //Use instead of Bootstrap's helper + box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.15); //Use instead of Bootstrap's helper } + &.make-tall { height: 100vh; display: flex; flex-direction: column; } - .prevent-squish{ + + .prevent-squish { overflow-x: unset; } } + .pointer { cursor: pointer; } + .container, .container-fluid { overflow: hidden; } - .sub-container{ + + .sub-container { &.make-tall { height: 100%; width: 100%; @@ -34,6 +41,7 @@ body { overflow-x: hidden; } } + .sr-only { position: absolute; left: -10000px; @@ -42,21 +50,29 @@ body { height: 1px; overflow: hidden; } + .page-container-grouped-styles { @extend .container-fluid, .shadow, .p-0, .position-relative, .make-tall; } + //Footer modal backdrop adjustments for positioning .modal-backdrop { left: 50%; transform: translateX(-50%); max-width: 576px; height: calc(100% - 72px); + + &.show { + opacity: 0.4; + } } + // Scroll page when modal isn't open .fade-on-route-transition { height: calc(100% - 10px); overflow: auto; } + // Prevent scroll when modal is open &.modal-open { .fade-on-route-transition { @@ -73,4 +89,4 @@ body { line-height: 24px; font-weight: 500; } -} +} \ No newline at end of file diff --git a/src/styles/common-typography-styles.scss b/src/styles/common-typography-styles.scss index a593092e..162f4a16 100644 --- a/src/styles/common-typography-styles.scss +++ b/src/styles/common-typography-styles.scss @@ -8,27 +8,38 @@ body { //Headings //add helper fw-bold to any element to get bold style (500) -h1,.h1 { +h1, +.h1 { line-height: 1.325; font-weight: 300; } -h2,.h2 { + +h2, +.h2 { line-height: 1.325; font-weight: 300; } -h3,.h3 { + +h3, +.h3 { line-height: 1.375; font-weight: 300; } -h4,.h4 { + +h4, +.h4 { line-height: 1.6; font-weight: 300; } -h5,.h5 { - line-height: 1.6; + +h5, +.h5 { + line-height: 1.325; font-weight: 400; } -h6,.h6 { + +h6, +.h6 { line-height: 1.7; letter-spacing: .75px; text-transform: uppercase; @@ -64,4 +75,4 @@ caption, font-size: 1rem !important; line-height: 1.4; font-weight: 500; -} +} \ No newline at end of file diff --git a/src/ux-components/alert/alert.vue b/src/ux-components/alert/alert.vue index 6a10fa41..6f2fa80a 100644 --- a/src/ux-components/alert/alert.vue +++ b/src/ux-components/alert/alert.vue @@ -14,19 +14,14 @@ v-for="paragraph in splitAlertCopyForParagraphTag" :key="paragraph">

- Date: Mon, 4 Dec 2023 21:26:34 -0500 Subject: [PATCH 410/674] Reverting change --- src/layouts/tpa-search/tpa-search.vue | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue index 814f712b..1ccd1926 100644 --- a/src/layouts/tpa-search/tpa-search.vue +++ b/src/layouts/tpa-search/tpa-search.vue @@ -90,14 +90,14 @@ alertClass="alert-warning" :isDismissible="false" :manualHeadline="noNetworkShopsAlertHeaderText" /> -

- -
+
+
+
From 17c40b058cc7fdf119be7088516fa414eb1a4448 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Dec 2023 23:14:19 -0500 Subject: [PATCH 411/674] Minor adjustment --- .../textbox-question/textbox-question.vue | 2 +- src/layouts/tpa-search/tpa-search.vue | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 86bcfeea..31d912a0 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -265,7 +265,7 @@ input[type='date']::-webkit-calendar-picker-indicator { } span { font-weight: 400; - font-size: 14px; + font-size: 0.875rem; color: #4d5151; } .form-test-error span { diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue index 1ccd1926..f7e9ecfe 100644 --- a/src/layouts/tpa-search/tpa-search.vue +++ b/src/layouts/tpa-search/tpa-search.vue @@ -13,7 +13,7 @@
@@ -23,19 +29,26 @@ + + diff --git a/src/layouts/payment-method/review-dropdown/review-block/review-block.vue b/src/layouts/payment-method/review-dropdown/review-block/review-block.vue new file mode 100644 index 00000000..fbc3ab08 --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-block/review-block.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/src/layouts/payment-method/review-dropdown/review-dropdown.vue b/src/layouts/payment-method/review-dropdown/review-dropdown.vue new file mode 100644 index 00000000..39c53005 --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-dropdown.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js new file mode 100644 index 00000000..1e0f612d --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js @@ -0,0 +1,129 @@ +// Components +import customerReview from '@/layouts/review-page/review-sections/customer-review/customer-review.vue'; + +// Supporting Files +import { shallowMount } from '@vue/test-utils'; +import { getMountOptions } from '@/helpers/unit-test-helper.js'; + +const testConstants = { + cms: { + header: { + text: 'Header' + }, + sms: { + text: 'Sms' + } + }, + customer: { + firstName: 'First', + lastName: 'Last', + phoneNumber: '111-111-1111', + emailAddress: 'builddigitaltest@safelite.com', + isSmsOptIn: false + }, + displayContent: { + fullName: 'First Last', + phoneNumber: '111-111-1111', + emailAddress: 'builddigitaltest@safelite.com', + smsOptIn: 'Sms' + } +}; + +function generateDefaultProps() { + return { + cmsWidgetName: 'CustomerWidget', + customer: { + firstName: testConstants.customer.firstName, + lastName: testConstants.customer.lastName, + phoneNumber: testConstants.customer.phoneNumber, + emailAddress: testConstants.customer.emailAddress, + isSmsOptIn: testConstants.customer.isSmsOptIn + } + }; +} + +let cmsContent; +const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '') + } +}; + +function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + + methodToRun(); + + mountOptions.data = () => ( + initialData + ); + + mountOptions.mixins = [mockMixin]; + + const wrapper = shallowMount(customerReview, mountOptions); + return { wrapper }; +} + +beforeEach(() => { + cmsContent = { + CustomerWidget: { + HeaderText: testConstants.cms.header.text, + SubheaderText: testConstants.cms.sms.text + } + }; +}); + +describe('Customer Review Block', () => { + test('Should display header text from cms', async () => { + // Arrange + const props = generateDefaultProps(); + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.header).toEqual(testConstants.cms.header.text); + }); + + test('Should display sms text from cms', async () => { + // Arrange + const props = generateDefaultProps(); + + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.text); + }); + + test('Should render correct display content', async () => { + // Arrange + const props = generateDefaultProps(); + + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toEqual([ + testConstants.displayContent.fullName, + testConstants.displayContent.emailAddress, + testConstants.displayContent.phoneNumber, + testConstants.displayContent.smsOptIn + ]); + }); +}); diff --git a/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.vue new file mode 100644 index 00000000..3d92e63c --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js new file mode 100644 index 00000000..b7a36442 --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js @@ -0,0 +1,436 @@ +// Components +import damageReview from '@/layouts/review-page/review-sections/damage-review/damage-review.vue'; + +// Supporting Files +import { shallowMount } from '@vue/test-utils'; +import { getMountOptions } from '@/helpers/unit-test-helper.js'; +import damageLocationsSelected from '@/constants/damage-locations-selected'; + +const testConstants = { + cmsConstants: { + widgetNames: { + header: 'DamageReviewWidget', + locations: 'DamageLocationsWidget', + driverDamages: 'DriverDamagesWidget', + passengerDamages: 'PassengerDamagesWidget' + }, + header: { + text: 'Damage' + }, + damageLocations: { + windshield: damageLocationsSelected.WINDSHIELD, + driver: damageLocationsSelected.DRIVER, + passenger: damageLocationsSelected.PASSENGER, + rear: damageLocationsSelected.REAR + }, + damageNames: { + vent: damageLocationsSelected.VENT, + front: damageLocationsSelected.FRONT, + back: damageLocationsSelected.BACK, + quarter: damageLocationsSelected.QUARTER, + side: damageLocationsSelected.SIDEDOOR + }, + locationCopy: { + windshield: 'Windshield copy', + driver: 'Driver copy', + passenger: 'Passenger copy', + rear: 'Rear copy' + }, + damageCopy: { + vent: 'Vent copy', + front: 'Front copy', + back: 'Back copy', + quarter: 'Quarter copy', + side: 'Side copy' + }, + imageId: '00000000-0000-0000-0000-000000000000' + }, + makeBulletedList: (items) => { + let list = '
    '; + items.forEach((item) => { + list += `
  • ${item}
  • `; + }); + list += '
'; + + return list; + }, + glassItems: { + windshield: { + glassLocation: damageLocationsSelected.WINDSHIELD, + glassName: damageLocationsSelected.SINGLE + }, + rear: { + glassLocation: damageLocationsSelected.REAR, + glassName: damageLocationsSelected.STATIONARY + }, + passengerItems: { + vent: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.VENT + }, + front: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.FRONT + }, + back: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.BACK + }, + quarter: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.QUARTER + }, + side: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.SIDEDOOR + } + }, + driverItems: { + vent: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.VENT + }, + front: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.FRONT + }, + back: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.BACK + }, + quarter: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.QUARTER + }, + side: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.SIDEDOOR + } + } + } +}; + +let cmsContent; +const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '') + } +}; + +function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + + methodToRun(); + + mountOptions.data = () => ( + initialData + ); + + mountOptions.mixins = [mockMixin]; + + const wrapper = shallowMount(damageReview, mountOptions); + return { wrapper }; +} + +beforeEach(() => { + cmsContent = { + DamageReviewWidget: { + Text: testConstants.cmsConstants.header.text + }, + DamageLocationsWidget: { + Answers: [ + { + Name: testConstants.cmsConstants.damageLocations.windshield, + Text: testConstants.cmsConstants.locationCopy.windshield, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageLocations.driver, + Text: testConstants.cmsConstants.locationCopy.driver, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: testConstants.cmsConstants.widgetNames.driverDamages + }, + { + Name: testConstants.cmsConstants.damageLocations.passenger, + Text: testConstants.cmsConstants.locationCopy.passenger, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: testConstants.cmsConstants.widgetNames.passengerDamages + }, + { + Name: testConstants.cmsConstants.damageLocations.rear, + Text: testConstants.cmsConstants.locationCopy.rear, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + } + ] + }, + DriverDamagesWidget: { + Answers: [ + { + Name: testConstants.cmsConstants.damageNames.vent, + Text: testConstants.cmsConstants.damageCopy.vent, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.front, + Text: testConstants.cmsConstants.damageCopy.front, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.back, + Text: testConstants.cmsConstants.damageCopy.back, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.quarter, + Text: testConstants.cmsConstants.damageCopy.quarter, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.side, + Text: testConstants.cmsConstants.damageCopy.side, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + } + ] + }, + PassengerDamagesWidget: { + Answers: [ + { + Name: testConstants.cmsConstants.damageNames.vent, + Text: testConstants.cmsConstants.damageCopy.vent, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.front, + Text: testConstants.cmsConstants.damageCopy.front, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.back, + Text: testConstants.cmsConstants.damageCopy.back, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.quarter, + Text: testConstants.cmsConstants.damageCopy.quarter, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.side, + Text: testConstants.cmsConstants.damageCopy.side, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + } + ] + } + }; +}); + +describe('Damage Review Block', () => { + describe('Correctly assembles damage info into a display string', () => { + test('Shows windshield copy when windshield damage is included', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent({ + cmsWidgetName: testConstants.cmsConstants.widgetNames.header, + damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, + damage: { + isRepair: false, + glassToReplace: [testConstants.glassItems.windshield] + } + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toStrictEqual([ + testConstants.cmsConstants.locationCopy.windshield + ]); + }); + + test('Windshield copy is shown when order is a repair', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent({ + cmsWidgetName: testConstants.cmsConstants.widgetNames.header, + damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, + damage: { + isRepair: true, + numberOfChips: 2, + glassToReplace: [] + } + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toStrictEqual([ + testConstants.cmsConstants.locationCopy.windshield + ]); + }); + + test('Rear windshield copy shows when rear damage is present', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent({ + cmsWidgetName: testConstants.cmsConstants.widgetNames.header, + damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, + damage: { + isRepair: false, + numberOfChips: null, + glassToReplace: [testConstants.glassItems.rear] + } + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toStrictEqual([ + testConstants.cmsConstants.locationCopy.rear + ]); + }); + + test('Driver side copy and items are shown when driver side damage is present', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent({ + cmsWidgetName: testConstants.cmsConstants.widgetNames.header, + damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, + damage: { + isRepair: false, + numberOfChips: null, + glassToReplace: [ + testConstants.glassItems.driverItems.back, + testConstants.glassItems.driverItems.front + ] + } + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toStrictEqual([ + testConstants.cmsConstants.locationCopy.driver, + testConstants.makeBulletedList([ + testConstants.cmsConstants.damageCopy.front, + testConstants.cmsConstants.damageCopy.back + ]) + ]); + }); + + test('Passenger side copy and items are shown when passenger side damage is present', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent({ + cmsWidgetName: testConstants.cmsConstants.widgetNames.header, + damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, + damage: { + isRepair: false, + numberOfChips: null, + glassToReplace: [ + testConstants.glassItems.passengerItems.quarter, + testConstants.glassItems.passengerItems.vent, + testConstants.glassItems.passengerItems.side + ] + } + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toStrictEqual([ + testConstants.cmsConstants.locationCopy.passenger, + testConstants.makeBulletedList([ + testConstants.cmsConstants.damageCopy.vent, + testConstants.cmsConstants.damageCopy.quarter, + testConstants.cmsConstants.damageCopy.side + ]) + ]); + }); + + test('All relevant sections are shown in order in multiglass scenario', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent({ + cmsWidgetName: testConstants.cmsConstants.widgetNames.header, + damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, + damage: { + isRepair: false, + numberOfChips: null, + glassToReplace: [ + testConstants.glassItems.windshield, + testConstants.glassItems.rear, + testConstants.glassItems.driverItems.vent, + testConstants.glassItems.driverItems.front, + testConstants.glassItems.driverItems.back, + testConstants.glassItems.passengerItems.quarter, + testConstants.glassItems.passengerItems.back, + testConstants.glassItems.passengerItems.side + ] + } + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toStrictEqual([ + testConstants.cmsConstants.locationCopy.windshield, + testConstants.cmsConstants.locationCopy.driver, + testConstants.makeBulletedList([ + testConstants.cmsConstants.damageCopy.vent, + testConstants.cmsConstants.damageCopy.front, + testConstants.cmsConstants.damageCopy.back + ]), + testConstants.cmsConstants.locationCopy.passenger, + testConstants.makeBulletedList([ + testConstants.cmsConstants.damageCopy.back, + testConstants.cmsConstants.damageCopy.quarter, + testConstants.cmsConstants.damageCopy.side + ]), + testConstants.cmsConstants.locationCopy.rear + ]); + }); + }); +}); diff --git a/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue new file mode 100644 index 00000000..589862c0 --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue @@ -0,0 +1,128 @@ + + + diff --git a/src/layouts/payment-method/review-dropdown/review-sections/schedule-review/schedule-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/schedule-review/schedule-review.vue new file mode 100644 index 00000000..e0c615df --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/schedule-review/schedule-review.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.spec.js new file mode 100644 index 00000000..834714aa --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.spec.js @@ -0,0 +1,134 @@ +// Components +import serviceLocationReview from '@/layouts/review-page/review-sections/service-location-review/service-location-review.vue'; + +// Supporting Files +import { shallowMount } from '@vue/test-utils'; +import { getMountOptions } from '@/helpers/unit-test-helper.js'; +import { AppointmentTypeStrings } from '@/constants/schedule-constants'; + +const cmsContent = { + ServiceLocationTitleWidget: { + Text: 'Title Text' + } +}; + +const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '') + } +}; + +function generateDefaultProps() { + return { + cmsWidgetName: 'ServiceLocationTitleWidget', + serviceLocation: { + address: 'Mobile Address 1', + address2: 'Mobile Address 2', + city: 'Mobile City', + state: 'MO', + zipCode: '11111', + zipCodeCtu: '', + appointmentType: AppointmentTypeStrings.MOBILE, + isVehicleProtected: false, + provider: { + providerNumber: '', + address: { + streetAddress: 'Service Location Address', + city: 'Service Location City', + state: 'SL', + zipCode: '22222', + zipCodeCtu: '' + } + } + } + }; +} + +function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + + methodToRun(); + + mountOptions.data = () => ( + initialData + ); + + mountOptions.mixins = [mockMixin]; + + const wrapper = shallowMount(serviceLocationReview, mountOptions); + return { wrapper }; +} + +describe('Service Location Review Block', () => { + test('Should render mobile address if mobile appointment', async () => { + // Arrange + const props = generateDefaultProps(); + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toEqual([ + 'Mobile Address 1, Mobile Address 2, Mobile City, MO 11111' + ]); + }); + + test('Should render service location address if inshop appointment.', async () => { + // Arrange + const props = generateDefaultProps(); + props.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP; + + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toEqual([ + 'Service Location Address, Service Location City, SL 22222' + ]); + }); + + test('Should render service location address if drop-off appointment', async () => { + // Arrange + const props = generateDefaultProps(); + props.serviceLocation.appointmentType = AppointmentTypeStrings.DROP_OFF; + + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toEqual([ + 'Service Location Address, Service Location City, SL 22222' + ]); + }); + + test('Should not add comma or any text if address2 is null', async () => { + // Arrange + const props = generateDefaultProps(); + props.serviceLocation.address2 = null; + + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toEqual(['Mobile Address 1, Mobile City, MO 11111']); + }); +}); diff --git a/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.vue new file mode 100644 index 00000000..17cc66cc --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.vue @@ -0,0 +1,51 @@ + + + diff --git a/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.spec.js new file mode 100644 index 00000000..6dfd6f4e --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.spec.js @@ -0,0 +1,969 @@ +// Components +import servicePackageReview from '@/layouts/review-page/review-sections/service-package-review/service-package-review.vue'; + +// Supporting Files +import { shallowMount } from '@vue/test-utils'; +import { getMountOptions } from '@/helpers/unit-test-helper.js'; +import packageNames from '@/constants/package-names'; +import partTypeStrings from '@/constants/part-type-strings'; +import damageLocationsSelected from '@/constants/damage-locations-selected'; + +const testConstants = { + cmsPropValues: { + servicePackageOptionsCmsName: 'ServicePackageTitle', + defaultPackageItemsCmsName: 'DefaultPackageItemDescriptions', + vapsItemsCmsName: 'VapsItemDescriptions' + }, + widgetNames: { + tierOneTitle: 'EconomyServiceTitle', + tierTwoTitle: 'StandardServiceTitle', + tierThreeTitle: 'PremiumServiceTitle' + }, + defaultItemCopy: { + itemOne: 'Item Description 1', + itemTwo: 'Item Description 2', + itemThree: 'Item Description 3', + itemFour: 'Item Description 4', + defaultItemCopyArray: ['Item Description 1', 'Item Description 2', 'Item Description 3'] + }, + vapsCopy: { + frontWiperCopy: 'Front Wiper copy', + rearWiperCopy: 'Rear Wiper copy', + rainDefenseCopy: 'Rain defense copy' + }, + parts: { + frontWiperPart: { + partNumber: 'SBB16', + description: 'SAFELITE BEAM BLADE 16', + partType: 'FRONT WIPER', + price: 32.64 + }, + rearWiperPart: { + partNumber: 'SBBR12A', + description: 'SAFELITE REAR BLADE 12A', + partType: 'REAR WIPER', + price: 24.48 + }, + rainDefensePart: { + partNumber: 'RAIN DEFENSE', + description: null, + partType: 'RAIN DEFENSE', + price: 35.5 + }, + recalPart: { + partNumber: 'RECAL STATIC', + Description: 'Recalibration', + partType: 'recalibration', + Quantity: '1', + price: 150.0 + } + }, + damages: { + frontWindshield: { + glassLocation: damageLocationsSelected.WINDSHIELD, + glassName: damageLocationsSelected.SINGLE + }, + rearWindshield: { + glassLocation: damageLocationsSelected.REAR, + glassName: damageLocationsSelected.STATIONARY + }, + sideGlass: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.QUARTER + } + }, + imageId: '00000000-0000-0000-0000-000000000000' +}; + +const figmaScenarios = [ + { + name: '05_01_CSR_Quote_Cash', + params: { + wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.frontWindshield] + }, + glassParts: [], + supportingItems: [] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Standard', + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy + ] + } + }, + { + name: 'Premium', + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Standard+RearWiper', + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy + ] + } + } + ] + }, + { + name: '05_01_CSR_Quote_Standard_Repair', + params: { + wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: true, + glassToReplace: [] + }, + glassParts: [], + supportingItems: [] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Standard', + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy + ] + } + }, + { + name: 'Premium', + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Standard+RearWiper', + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy + ] + } + } + ] + }, + { + name: '05_01_CSR_Quote_Recal', + params: { + wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.frontWindshield] + }, + glassParts: [], + supportingItems: [testConstants.parts.recalPart] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Standard', + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy + ] + } + }, + { + name: 'Premium', + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Standard+RearWiper', + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy + ] + } + } + ] + }, + // 05_01_CSR_Quote_RearGlass omitted as a duplicate of below. + { + name: '05_01_CSR_Quote_RearGlass+NonWindshield', + params: { + wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.rearWindshield] + }, + glassParts: [], + supportingItems: [] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Economy+Frontwiper', + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy + ] + } + }, + { + name: 'Standard', + vapsCombo: [testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy + ] + } + }, + { + name: 'Standard+RainDefense', + vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Premium', + vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy + ] + } + } + ] + }, + { + name: '05_01_CSR_Quote_RearGlass+Windshield', + params: { + wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: false, + glassToReplace: [ + testConstants.damages.frontWindshield, + testConstants.damages.rearWindshield + ] + }, + glassParts: [], + supportingItems: [] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Economy+Frontwiper', + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy + ] + } + }, + { + name: 'Economy+Rearwiper', + vapsCombo: [testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy + ] + } + }, + { + name: 'Economy+RainDefense', + vapsCombo: [testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Economy+Frontwiper+RainDefense', + vapsCombo: [ + testConstants.parts.frontWiperPart, + testConstants.parts.rainDefensePart + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Economy+Rearwiper+RainDefense', + vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Standard', + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy + ] + } + }, + { + name: 'Premium', + vapsCombo: [ + testConstants.parts.rearWiperPart, + testConstants.parts.frontWiperPart, + testConstants.parts.rainDefensePart + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + } + ] + }, + { + name: '05_01_CSR_Quote_RearGlassNoFrontFit', + params: { + wiperResponse: [testConstants.parts.rearWiperPart], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.rearWindshield] + }, + glassParts: [], + supportingItems: [] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Economy+Raindefense', + vapsCombo: [testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Standard', + vapsCombo: [testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy + ] + } + }, + { + name: 'Premium', + vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + } + ] + }, + // 05_01_CSR_Quote_Windshield+SideGlass has identical outcomes to 05_01_CSR_Quote_Cash, but included in case that changes in the future. + { + name: '05_01_CSR_Quote_Windshield+SideGlass', + params: { + wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: false, + glassToReplace: [ + testConstants.damages.frontWindshield, + testConstants.damages.sideGlass + ] + }, + glassParts: [], + supportingItems: [] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Standard', + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy + ] + } + }, + { + name: 'Premium', + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Standard+RearWiper', + vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierTwoTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy + ] + } + } + ] + }, + // Has no standard package + { + name: '05_01_CSR_Quote_SideGlass', + params: { + wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.sideGlass] + }, + glassParts: [], + supportingItems: [] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Economy+Frontwiper', + vapsCombo: [testConstants.parts.frontWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy + ] + } + }, + { + name: 'Economy+RainDefense', + vapsCombo: [testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Economy+Rearwiper', + vapsCombo: [testConstants.parts.rearWiperPart], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rearWiperCopy + ] + } + }, + { + name: 'Premium', + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + }, + { + name: 'Premium+Rearwiper', + vapsCombo: [ + testConstants.parts.rainDefensePart, + testConstants.parts.frontWiperPart, + testConstants.parts.rearWiperPart + ], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.frontWiperCopy, + testConstants.vapsCopy.rearWiperCopy, + testConstants.vapsCopy.rainDefenseCopy + ] + } + } + ] + }, + // Has no standard package + { + name: '05_01_CSR_Quote_NoWiperFit', + params: { + wiperResponse: [], + rainDefenseResponse: testConstants.parts.rainDefensePart, + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.frontWindshield] + }, + glassParts: [], + supportingItems: [] + }, + iterations: [ + { + name: 'Economy', + vapsCombo: [], + expected: { + packageNameWidget: testConstants.widgetNames.tierOneTitle, + displayContent: testConstants.defaultItemCopy.defaultItemCopyArray + } + }, + { + name: 'Premium', + vapsCombo: [testConstants.parts.rainDefensePart], + expected: { + packageNameWidget: testConstants.widgetNames.tierThreeTitle, + displayContent: [ + ...testConstants.defaultItemCopy.defaultItemCopyArray, + testConstants.vapsCopy.rainDefenseCopy + ] + } + } + ] + } +]; + +function generateDefaultProps() { + return { + servicePackageOptionsCmsName: testConstants.cmsPropValues.servicePackageOptionsCmsName, + defaultPackageItemsCmsName: testConstants.cmsPropValues.defaultPackageItemsCmsName, + vapsItemsCmsName: testConstants.cmsPropValues.vapsItemsCmsName, + lineItems: { + glassParts: [], + supportingItems: [], + vaps: [testConstants.parts.frontWiperPart] + }, + damage: { + isRepair: false, + glassToReplace: [testConstants.damages.frontWindshield] + } + }; +} + +let cmsContent; +const mockMixin = { + methods: { + getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '') + } +}; + +function initializeWithDefault(wrapper) { + wrapper.vm.initializeComponent({ + wipers: [testConstants.parts.frontWiperPart], + rainDefense: testConstants.parts.rainDefensePart + }); +} + +function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + + methodToRun(); + + mountOptions.data = () => ( + initialData + ); + + mountOptions.mixins = [mockMixin]; + + const wrapper = shallowMount(servicePackageReview, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} + +beforeEach(() => { + cmsContent = { + ServicePackageTitle: { + Answers: [ + { + Name: packageNames.TIER_ONE, + Text: '', + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: testConstants.widgetNames.tierOneTitle + }, + { + Name: packageNames.TIER_TWO, + Text: '', + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: testConstants.widgetNames.tierTwoTitle + }, + { + Name: packageNames.TIER_THREE, + Text: '', + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: testConstants.widgetNames.tierThreeTitle + } + ] + }, + DefaultPackageItemDescriptions: { + Answers: [ + { + Name: 'Item1', + Text: testConstants.defaultItemCopy.itemOne, + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: 'Item2', + Text: testConstants.defaultItemCopy.itemTwo, + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: 'Item3', + Text: testConstants.defaultItemCopy.itemThree, + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: '' + } + ] + }, + VapsItemDescriptions: { + Answers: [ + { + Name: partTypeStrings.FRONT_WIPER, + Text: testConstants.vapsCopy.frontWiperCopy, + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: partTypeStrings.REAR_WIPER, + Text: testConstants.vapsCopy.rearWiperCopy, + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: partTypeStrings.RAIN_DEFENSE, + Text: testConstants.vapsCopy.rainDefenseCopy, + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: '' + } + ] + } + }; +}); + +describe('Service Package Review Block', () => { + describe('General functionality', () => { + test('Should properly "Round Down" package tier', async () => { + // Slightly longer explanation: + // Should only return the highest tier where *every* offered VAP is part of the order. + // However, there may be vaps not offered in the qualifying tier. Hence rounding *down*. + // + // I.e. Economy=[], Standard=[front wipers], Premium=[front wipers, rain defense]. + // Current vaps=[rain defense]. Though rain defense is in Premium, we don't satisfy it or standard. + // So our tier should still be Economy. + // Should still display extra vaps. + + // Arrange + const props = generateDefaultProps(); + props.lineItems.vaps = [testConstants.parts.rainDefensePart]; + + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + initializeWithDefault(wrapper); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.packageNameWidget).toEqual(testConstants.widgetNames.tierOneTitle); + + const containsRainDefenseCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.rainDefenseCopy); + expect(containsRainDefenseCopy).toBe(true); + }); + + test('Should display all default items from cms', async () => { + // Arrange + cmsContent.DefaultPackageItemDescriptions.Answers.push({ + Name: 'Item4', + Text: testConstants.defaultItemCopy.itemFour, + SubText: '', + ImageId: testConstants.imageId, + Image: '', + SubWidgetName: '' + }); + + const props = generateDefaultProps(); + props.lineItems.vaps = []; + + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + initializeWithDefault(wrapper); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + const expectedResult = [ + testConstants.defaultItemCopy.itemOne, + testConstants.defaultItemCopy.itemTwo, + testConstants.defaultItemCopy.itemThree, + testConstants.defaultItemCopy.itemFour + ]; + + expect(wrapper.vm.displayContent).toEqual(expectedResult); + }); + + test('Should display vaps if and only if they are added', async () => { + // Arrange + const props = generateDefaultProps(); + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + // Act + await wrapper.vm.$nextTick(); + + initializeWithDefault(wrapper); + + // Assert + const includesFrontWiperCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.frontWiperCopy); + const includesRainDefenseCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.rainDefenseCopy); + expect(includesFrontWiperCopy).toBe(true); + expect(includesRainDefenseCopy).toBe(false); + }); + + test('Should not error if cms content is missing (though may display poorly).', async () => { + // Arrange + cmsContent = {}; + const props = generateDefaultProps(); + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + initializeWithDefault(wrapper); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.packageNameWidget).toEqual(''); + expect(wrapper.vm.displayContent).toEqual([]); + }); + }); + + describe('Match Figma Scenarios', () => { + figmaScenarios.forEach((scenario) => { + scenario.iterations.forEach((iteration) => { + it(`Should match figma scenario "${scenario.name}", iteration "${iteration.name}"`, async () => { + // Arrange + const props = generateDefaultProps(); + props.damage = scenario.params.damage; + props.glassParts = scenario.params.glassParts; + props.lineItems.supportingItems = scenario.params.supportingItems; + props.lineItems.vaps = iteration.vapsCombo; + + const { wrapper } = getShallowMountedComponent({ + ...props + }); + + wrapper.vm.initializeComponent({ + wipers: scenario.params.wiperResponse, + rainDefense: scenario.params.rainDefenseResponse + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.packageNameWidget).toEqual(iteration.expected.packageNameWidget); + expect(wrapper.vm.displayContent).toEqual(iteration.expected.displayContent); + }); + }); + }); + }); +}); diff --git a/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue new file mode 100644 index 00000000..6836f1f7 --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue @@ -0,0 +1,126 @@ + + + diff --git a/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js new file mode 100644 index 00000000..fd4a3d64 --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js @@ -0,0 +1,47 @@ +// Components +import vehicleReview from '@/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue'; + +// Supporting Files +import { shallowMount } from '@vue/test-utils'; +import { getMountOptions } from '@/helpers/unit-test-helper.js'; + +jest.mock('@/helpers/cms-content-helper', () => ({ + fetchCmsContentForPage: () => Promise.resolve('content') +})); + +function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + + methodToRun(); + + mountOptions.data = () => ( + initialData + ); + + const wrapper = shallowMount(vehicleReview, mountOptions); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} + +describe('Vehicle Review Block', () => { + test('Correctly assembles vehicle info into a display string', async () => { + // Arrange + const { wrapper } = getShallowMountedComponent({ + vehicle: { + year: '2019', + make: 'Honda', + model: 'Odyssey' + } + }); + + // Act + await wrapper.vm.$nextTick(); + + // Assert + expect(wrapper.vm.displayContent).toStrictEqual(['2019 Honda Odyssey']); + }); +}); diff --git a/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue new file mode 100644 index 00000000..56bee25e --- /dev/null +++ b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/styles/ux-variables-svg-strings.scss b/src/styles/ux-variables-svg-strings.scss index fbef8a3d..fba802db 100644 --- a/src/styles/ux-variables-svg-strings.scss +++ b/src/styles/ux-variables-svg-strings.scss @@ -1,10 +1,11 @@ +$svg-calendar-picker: "data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M14.1762 1.52764H13.7656V1.50352C13.7656 1.10476 13.6076 0.722334 13.3263 0.44037C13.0451 0.158406 12.6636 0 12.2659 0C11.8681 0 11.4866 0.158406 11.2054 0.44037C10.9241 0.722334 10.7661 1.10476 10.7661 1.50352V1.52764H5.42476V1.50352C5.42476 1.10476 5.26675 0.722334 4.9855 0.44037C4.70424 0.158406 4.32277 0 3.92501 0C3.52725 0 3.14579 0.158406 2.86453 0.44037C2.58327 0.722334 2.42526 1.10476 2.42526 1.50352V1.52764H1.82376C1.34046 1.52891 0.877316 1.72195 0.53557 2.06455C0.193824 2.40716 0.00127018 2.87146 0 3.35598V14.1717C0.0016909 14.656 0.194379 15.1201 0.536035 15.4626C0.87769 15.8051 1.34059 15.9983 1.82376 16H14.1746C14.6581 15.9987 15.1214 15.8057 15.4634 15.4632C15.8054 15.1206 15.9983 14.6563 16 14.1717V3.35598C15.9987 2.87146 15.8062 2.40716 15.4644 2.06455C15.1227 1.72195 14.6595 1.52891 14.1762 1.52764ZM11.8889 1.50352C11.8889 1.4033 11.9286 1.30718 11.9993 1.23631C12.07 1.16544 12.1659 1.12563 12.2659 1.12563C12.3658 1.12563 12.4617 1.16544 12.5324 1.23631C12.6031 1.30718 12.6428 1.4033 12.6428 1.50352V2.99899C12.6428 3.09922 12.6031 3.19534 12.5324 3.2662C12.4617 3.33707 12.3658 3.37688 12.2659 3.37688C12.1659 3.37688 12.07 3.33707 11.9993 3.2662C11.9286 3.19534 11.8889 3.09922 11.8889 2.99899V1.50352ZM3.54807 1.50352C3.54807 1.4033 3.58778 1.30718 3.65847 1.23631C3.72916 1.16544 3.82504 1.12563 3.92501 1.12563C4.02498 1.12563 4.12086 1.16544 4.19155 1.23631C4.26224 1.30718 4.30195 1.4033 4.30195 1.50352V2.99899C4.30195 3.09922 4.26224 3.19534 4.19155 3.2662C4.12086 3.33707 4.02498 3.37688 3.92501 3.37688C3.82504 3.37688 3.72916 3.33707 3.65847 3.2662C3.58778 3.19534 3.54807 3.09922 3.54807 2.99899V1.50352ZM14.8772 14.1717C14.8747 14.3573 14.8001 14.5345 14.6691 14.6658C14.5382 14.797 14.3614 14.8719 14.1762 14.8744H1.82536C1.63995 14.8723 1.4627 14.7976 1.33144 14.6663C1.20018 14.5351 1.12531 14.3575 1.12281 14.1717V6.59296H14.8772V14.1717Z' fill='%23167CAC'/%3E%3Cpath d='M2.33063 11.282H3.93464V12.6006C3.93464 12.7499 3.99379 12.8931 4.09907 12.9986C4.20435 13.1041 4.34715 13.1634 4.49604 13.1634C4.64494 13.1634 4.78773 13.1041 4.89301 12.9986C4.9983 12.8931 5.05745 12.7499 5.05745 12.6006V11.282H7.46346V12.6006C7.46346 12.7499 7.52261 12.8931 7.62789 12.9986C7.73318 13.1041 7.87597 13.1634 8.02486 13.1634C8.17376 13.1634 8.31655 13.1041 8.42184 12.9986C8.52712 12.8931 8.58627 12.7499 8.58627 12.6006V11.282H10.9923V12.6006C10.9923 12.7499 11.0514 12.8931 11.1567 12.9986C11.262 13.1041 11.4048 13.1634 11.5537 13.1634C11.7026 13.1634 11.8454 13.1041 11.9507 12.9986C12.0559 12.8931 12.1151 12.7499 12.1151 12.6006V11.282H13.7191C13.868 11.282 14.0108 11.2227 14.1161 11.1172C14.2214 11.0116 14.2805 10.8685 14.2805 10.7192C14.2805 10.57 14.2214 10.4268 14.1161 10.3213C14.0108 10.2157 13.868 10.1564 13.7191 10.1564H12.1151V8.84425C12.1151 8.69498 12.0559 8.55183 11.9507 8.44628C11.8454 8.34073 11.7026 8.28143 11.5537 8.28143C11.4048 8.28143 11.262 8.34073 11.1567 8.44628C11.0514 8.55183 10.9923 8.69498 10.9923 8.84425V10.1628H8.58627V8.84425C8.58627 8.69498 8.52712 8.55183 8.42184 8.44628C8.31655 8.34073 8.17376 8.28143 8.02486 8.28143C7.87597 8.28143 7.73318 8.34073 7.62789 8.44628C7.52261 8.55183 7.46346 8.69498 7.46346 8.84425V10.1628H5.05745V8.84425C5.05745 8.69498 4.9983 8.55183 4.89301 8.44628C4.78773 8.34073 4.64494 8.28143 4.49604 8.28143C4.34715 8.28143 4.20435 8.34073 4.09907 8.44628C3.99379 8.55183 3.93464 8.69498 3.93464 8.84425V10.1628H2.33063C2.18174 10.1628 2.03894 10.2221 1.93366 10.3277C1.82837 10.4332 1.76923 10.5764 1.76923 10.7257C1.76923 10.8749 1.82837 11.0181 1.93366 11.1236C2.03894 11.2292 2.18174 11.2885 2.33063 11.2885V11.282Z' fill='%23167CAC'/%3E%3C/svg%3E"; $svg-date-picker-nav-back-button: "data:image/svg+xml,%3Csvg width='7' height='12' viewBox='0 0 7 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.331685 6.00121C0.330445 5.82446 0.399256 5.65442 0.523053 5.52832L5.84499 0.198256C5.97188 0.0713149 6.14397 -8.63821e-08 6.32341 -6.72174e-08C6.50285 -4.80527e-08 6.67495 0.071315 6.80183 0.198256C6.92872 0.325198 7 0.497368 7 0.67689C7 0.856412 6.92872 1.02858 6.80183 1.15552L1.94874 6.00121L6.80183 10.8526C6.92745 10.9796 6.99751 11.1512 6.99662 11.3299C6.99572 11.5085 6.92393 11.6794 6.79705 11.8051C6.67016 11.9308 6.49857 12.0009 6.32003 12C6.14148 11.9991 5.97061 11.9273 5.84499 11.8003L0.526881 6.47601C0.401568 6.34983 0.331375 6.17908 0.331685 6.00121Z' fill='%231574A1'/%3E%3C/svg%3E%0A"; $svg-date-picker-forward-button: "data:image/svg+xml,%3Csvg width='7' height='12' viewBox='0 0 7 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.66831 5.99879C6.66955 6.17554 6.60074 6.34558 6.47695 6.47168L1.15501 11.8017C1.02812 11.9287 0.85603 12 0.676587 12C0.497145 12 0.325053 11.9287 0.198168 11.8017C0.0712831 11.6748 7.268e-09 11.5026 8.07183e-09 11.3231C8.87567e-09 11.1436 0.0712831 10.9714 0.198168 10.8445L5.05126 5.99879L0.198168 1.14736C0.0725521 1.02042 0.00248585 0.848755 0.00338306 0.670131C0.00428028 0.491506 0.0760674 0.320554 0.202952 0.194881C0.329837 0.0692091 0.501426 -0.000888818 0.679971 9.54485e-06C0.858515 0.000906955 1.02939 0.0727263 1.15501 0.199668L6.47312 5.52399C6.59843 5.65017 6.66862 5.82092 6.66831 5.99879Z' fill='%231574A1'/%3E%3C/svg%3E%0A"; $svg-drop-off-alert: "data:image/svg+xml,%3Csvg viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0_13957_112512)'%3E%3Cpath d='M5.99865 0C4.81147 4.82643e-07 3.65095 0.352111 2.66392 1.01179C1.67688 1.67146 0.907678 2.60907 0.45361 3.70599C-0.000459241 4.80291 -0.11899 6.00986 0.113013 7.17415C0.345015 8.33845 0.917126 9.40778 1.75697 10.2469C2.59682 11.086 3.66666 11.6571 4.83117 11.8881C5.99567 12.119 7.20251 11.9994 8.29902 11.5443C9.39553 11.0893 10.3324 10.3192 10.9912 9.33159C11.65 8.34396 12.0011 7.18313 12 5.99594C11.9971 4.40566 11.3638 2.88142 10.2388 1.75742C9.11375 0.633431 7.58894 0.00143011 5.99865 0V0ZM5.99865 11.2478C4.96135 11.2473 3.94748 10.9392 3.08518 10.3627C2.22288 9.7861 1.55085 8.96685 1.15401 8.00846C0.75718 7.05006 0.653353 5.99554 0.855656 4.97815C1.05796 3.96077 1.55731 3.02618 2.29061 2.29251C3.0239 1.55884 3.95823 1.059 4.97551 0.856176C5.99279 0.653349 7.04737 0.756633 8.00597 1.15297C8.96457 1.54931 9.78416 2.22092 10.3612 3.08293C10.9382 3.94493 11.2467 4.95864 11.2478 5.99594C11.2478 7.38835 10.6949 8.72377 9.71053 9.70861C8.7262 10.6934 7.39106 11.2471 5.99865 11.2478V11.2478Z' fill='%2306577C'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M6.22736 8.84695C6.30613 8.76818 6.35038 8.66135 6.35038 8.54996V5.30996C6.35038 5.19857 6.30613 5.09174 6.22736 5.01298C6.1486 4.93421 6.04177 4.88996 5.93038 4.88996C5.81899 4.88996 5.71216 4.93421 5.63339 5.01298C5.55463 5.09174 5.51038 5.19857 5.51038 5.30996V8.54996C5.51038 8.66135 5.55463 8.76818 5.63339 8.84695C5.71216 8.92571 5.81899 8.96996 5.93038 8.96996C6.04177 8.96996 6.1486 8.92571 6.22736 8.84695ZM5.69704 3.97918C5.76611 4.02533 5.84731 4.04996 5.93038 4.04996C5.98558 4.05012 6.04026 4.03936 6.09129 4.01831C6.14232 3.99726 6.18868 3.96633 6.22771 3.9273C6.26675 3.88827 6.29768 3.8419 6.31873 3.79088C6.33978 3.73985 6.35053 3.68516 6.35038 3.62996C6.35038 3.54689 6.32574 3.46569 6.27959 3.39662C6.23344 3.32755 6.16785 3.27372 6.0911 3.24193C6.01436 3.21014 5.92991 3.20183 5.84844 3.21803C5.76697 3.23424 5.69213 3.27424 5.63339 3.33298C5.57465 3.39171 5.53465 3.46655 5.51845 3.54802C5.50224 3.6295 5.51056 3.71394 5.54235 3.79069C5.57414 3.86743 5.62797 3.93303 5.69704 3.97918Z' fill='%2306577C'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0_13957_112512'%3E%3Crect width='12' height='12' fill='white'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E%0A"; $svg-loading-modal-image: "data:image/svg+xml;charset=UTF-8,%3csvg fill='none' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 84 32'%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' fill='%23fff'/%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' fill='%23fff'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06.8c8.08 0 11.89.935 11.89.935 3.58.576 5.696 7.207 5.696 7.207h.727c0-2.427 1.302-2.397 2.341-2 .723.292 1.363.76 1.86 1.361 1.319 1.547.465 1.674.465 1.674h-5.067l3.846 3.01v12.016c0 2.41-2.029 2.31-2.029 2.31H22.338s-2.029.1-2.029-2.31V12.996l3.84-3.009H19.07s-.853-.127.466-1.674a4.693 4.693 0 0 1 1.86-1.361c1.032-.397 2.341-.427 2.341 2h.736s2.117-6.64 5.696-7.21c0 0 3.81-.942 11.89-.942Z' fill='%23fff' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06 8.847c7.924 0 14.685.511 14.685.511 0-2.585-2.38-6.011-2.38-6.011S50.4 2.519 42.06 2.519s-12.303.828-12.303.828-2.38 3.426-2.38 6.011c0 0 6.76-.51 14.683-.51Z' fill='%23DA291C' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M35.277 16.523a62.558 62.558 0 0 1 13.277 0m3.276-.439s2.384-2.257 8.608-2.257c0 0 1.179 2.657-2.54 3.37m-25.894-1.113s-2.387-2.257-8.611-2.257c0 0-1.16 2.579 2.543 3.37m-3.546 5.856s21.52 3.647 39.123 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e"; -$svg-shop-list-button-green-availability: "data:image/svg+xml,%3Csvg viewBox='0 0 13 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.5 12C3.19159 12 0.5 9.30841 0.5 6C0.5 2.69159 3.19159 0 6.5 0C9.80841 0 12.5 2.69159 12.5 6C12.5 9.30841 9.80841 12 6.5 12ZM6.5 0.785047C3.62449 0.785047 1.28505 3.12449 1.28505 6C1.28505 8.87551 3.62449 11.215 6.5 11.215C9.37551 11.215 11.715 8.87551 11.715 6C11.715 3.12449 9.37551 0.785047 6.5 0.785047Z' fill='%23006A36'/%3E%3Cpath d='M5.697 7.95252C5.5927 7.95252 5.49289 7.91102 5.41999 7.837L3.90597 6.32299C3.75233 6.16934 3.75233 5.92149 3.90597 5.76785C4.05962 5.6142 4.30747 5.6142 4.46111 5.76785L5.69812 7.00373L8.53999 4.16186C8.69364 4.00822 8.94149 4.00822 9.09513 4.16186C9.24878 4.31551 9.24878 4.56336 9.09513 4.717L5.97626 7.83588C5.90224 7.9099 5.80242 7.9514 5.69925 7.9514L5.697 7.95252Z' fill='%23006A36'/%3E%3C/svg%3E%0A"; -$svg-shop-list-button-orange-availability: "data:image/svg+xml,%3Csvg viewBox='0 0 13 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.5 0C9.81368 0 12.5 2.68632 12.5 6C12.5 9.31368 9.81368 12 6.5 12C3.18632 12 0.5 9.31368 0.5 6C0.5 2.68632 3.18632 0 6.5 0ZM6.5 0.84C3.6548 0.84 1.34 3.1548 1.34 6C1.34 8.8452 3.6548 11.16 6.5 11.16C9.3452 11.16 11.66 8.8452 11.66 6C11.66 3.1548 9.3452 0.84 6.5 0.84ZM7.90018 4.00596C8.06422 3.84204 8.33002 3.84192 8.49406 4.00596C8.6581 4.17 8.6581 4.43592 8.49406 4.59996L7.0939 6L8.49406 7.40004C8.6581 7.56408 8.6581 7.83 8.49406 7.99404C8.4121 8.076 8.30458 8.11704 8.19706 8.11704C8.08966 8.11704 7.98214 8.076 7.90018 7.99404L6.50002 6.594L5.09986 7.99404C5.01778 8.076 4.91038 8.11704 4.80286 8.11704C4.69546 8.11704 4.58794 8.076 4.50598 7.99404C4.34182 7.83 4.34182 7.56408 4.50598 7.40004L5.90614 6L4.50598 4.59996C4.34182 4.43592 4.34182 4.17 4.50598 4.00596C4.66978 3.84192 4.93582 3.84204 5.09986 4.00596L6.50002 5.406L7.90018 4.00596Z' fill='%23E86421'/%3E%3C/svg%3E%0A"; -$svg-update-zip-text-link: "data:image/svg+xml,%3Csvg viewBox='0 0 13 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.49635 1.00142e-07C5.64734 -0.000153295 4.80722 0.175918 4.0274 0.517444C3.24757 0.858969 2.54443 1.35877 1.96099 1.98626C0.765713 3.27588 0.0999756 4.98141 0.0999756 6.75394C0.0999756 8.52646 0.765713 10.232 1.96099 11.5216L5.98324 15.777C6.04954 15.8475 6.12918 15.9036 6.21736 15.9419C6.30555 15.9802 6.40045 16 6.49635 16C6.59225 16 6.68716 15.9802 6.77534 15.9419C6.86353 15.9036 6.94317 15.8475 7.00946 15.777L11.0317 11.52C12.2391 10.2383 12.909 8.52914 12.8999 6.75394C12.9094 4.97818 12.2394 3.26832 11.0317 1.98626C10.4481 1.35899 9.74493 0.859347 8.96514 0.517839C8.18535 0.176331 7.34532 0.000130509 6.49635 1.00142e-07V1.00142e-07ZM6.49635 9.13131C6.02507 9.13131 5.56437 8.98913 5.17251 8.72275C4.78065 8.45637 4.47524 8.07776 4.29488 7.63479C4.11453 7.19181 4.06734 6.70438 4.15928 6.23412C4.25123 5.76387 4.47817 5.33191 4.81142 4.99287C5.14467 4.65384 5.56925 4.42295 6.03148 4.32941C6.49371 4.23587 6.97282 4.28388 7.40823 4.46736C7.84364 4.65085 8.21579 4.96157 8.47762 5.36023C8.73945 5.7589 8.87921 6.2276 8.87921 6.70707C8.87921 7.34974 8.62837 7.96611 8.18185 8.4207C7.73532 8.87528 7.12964 9.13088 6.49794 9.13131H6.49635Z' fill='%231574A1'/%3E%3C/svg%3E%0A"; +$svg-payment-method-review-toggle: "data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.9' xml:space='preserve'%3e%3cpath d='M8 8.9c-.2 0-.5-.1-.6-.3L.3 1.5C.1 1.4 0 1.1 0 .9 0 .7.1.4.3.3.4.1.7 0 .9 0c.2 0 .5.1.6.3L8 6.7 14.5.2c.1-.1.4-.2.6-.2.2 0 .5.1.6.3s.3.4.3.6c0 .2-.1.5-.3.6L8.6 8.6c-.1.2-.4.3-.6.3z' fill='%231474a2'/%3e%3c/svg%3e"; $svg-search-icon: "data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15.7817 14.7328L11.8252 10.7762C12.8833 9.45005 13.3936 7.76911 13.2513 6.07849C13.1091 4.38788 12.325 2.81587 11.0601 1.6852C9.79515 0.554524 8.14538 -0.0490261 6.44946 -0.00154744C4.75353 0.0459312 3.14012 0.740836 1.94045 1.94051C0.740775 3.14018 0.0458701 4.75359 -0.00160848 6.44952C-0.0490871 8.14545 0.554463 9.79521 1.68514 11.0601C2.81581 12.325 4.38782 13.1091 6.07843 13.2514C7.76905 13.3937 9.44999 12.8834 10.7762 11.8252L14.7349 15.7839C14.8044 15.8527 14.8869 15.907 14.9774 15.9439C15.068 15.9808 15.165 15.9995 15.2628 15.9989C15.3606 15.9983 15.4573 15.9784 15.5475 15.9405C15.6376 15.9025 15.7194 15.8471 15.7881 15.7776C15.8568 15.708 15.9112 15.6256 15.9481 15.535C15.985 15.4444 16.0036 15.3474 16.0031 15.2496C16.0025 15.1518 15.9826 15.0551 15.9446 14.965C15.9067 14.8748 15.8513 14.7931 15.7817 14.7243V14.7328ZM6.63737 11.7913C5.61803 11.7913 4.62157 11.4891 3.77402 10.9228C2.92646 10.3564 2.26587 9.5515 1.87578 8.60975C1.4857 7.668 1.38363 6.63172 1.5825 5.63196C1.78136 4.6322 2.27222 3.71386 2.99301 2.99307C3.7138 2.27229 4.63214 1.78142 5.6319 1.58256C6.63166 1.38369 7.66793 1.48576 8.60969 1.87585C9.55144 2.26593 10.3564 2.92652 10.9227 3.77408C11.489 4.62163 11.7913 5.61809 11.7913 6.63743C11.7896 8.00382 11.2461 9.31376 10.2799 10.2799C9.3137 11.2461 8.00376 11.7897 6.63737 11.7913Z' fill='%231574A1'/%3E%3C/svg%3E%0A"; $svg-select-icon: "data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%231474a2'/%3e%3c/svg%3e"; -$svg-calendar-picker: "data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M14.1762 1.52764H13.7656V1.50352C13.7656 1.10476 13.6076 0.722334 13.3263 0.44037C13.0451 0.158406 12.6636 0 12.2659 0C11.8681 0 11.4866 0.158406 11.2054 0.44037C10.9241 0.722334 10.7661 1.10476 10.7661 1.50352V1.52764H5.42476V1.50352C5.42476 1.10476 5.26675 0.722334 4.9855 0.44037C4.70424 0.158406 4.32277 0 3.92501 0C3.52725 0 3.14579 0.158406 2.86453 0.44037C2.58327 0.722334 2.42526 1.10476 2.42526 1.50352V1.52764H1.82376C1.34046 1.52891 0.877316 1.72195 0.53557 2.06455C0.193824 2.40716 0.00127018 2.87146 0 3.35598V14.1717C0.0016909 14.656 0.194379 15.1201 0.536035 15.4626C0.87769 15.8051 1.34059 15.9983 1.82376 16H14.1746C14.6581 15.9987 15.1214 15.8057 15.4634 15.4632C15.8054 15.1206 15.9983 14.6563 16 14.1717V3.35598C15.9987 2.87146 15.8062 2.40716 15.4644 2.06455C15.1227 1.72195 14.6595 1.52891 14.1762 1.52764ZM11.8889 1.50352C11.8889 1.4033 11.9286 1.30718 11.9993 1.23631C12.07 1.16544 12.1659 1.12563 12.2659 1.12563C12.3658 1.12563 12.4617 1.16544 12.5324 1.23631C12.6031 1.30718 12.6428 1.4033 12.6428 1.50352V2.99899C12.6428 3.09922 12.6031 3.19534 12.5324 3.2662C12.4617 3.33707 12.3658 3.37688 12.2659 3.37688C12.1659 3.37688 12.07 3.33707 11.9993 3.2662C11.9286 3.19534 11.8889 3.09922 11.8889 2.99899V1.50352ZM3.54807 1.50352C3.54807 1.4033 3.58778 1.30718 3.65847 1.23631C3.72916 1.16544 3.82504 1.12563 3.92501 1.12563C4.02498 1.12563 4.12086 1.16544 4.19155 1.23631C4.26224 1.30718 4.30195 1.4033 4.30195 1.50352V2.99899C4.30195 3.09922 4.26224 3.19534 4.19155 3.2662C4.12086 3.33707 4.02498 3.37688 3.92501 3.37688C3.82504 3.37688 3.72916 3.33707 3.65847 3.2662C3.58778 3.19534 3.54807 3.09922 3.54807 2.99899V1.50352ZM14.8772 14.1717C14.8747 14.3573 14.8001 14.5345 14.6691 14.6658C14.5382 14.797 14.3614 14.8719 14.1762 14.8744H1.82536C1.63995 14.8723 1.4627 14.7976 1.33144 14.6663C1.20018 14.5351 1.12531 14.3575 1.12281 14.1717V6.59296H14.8772V14.1717Z' fill='%23167CAC'/%3E%3Cpath d='M2.33063 11.282H3.93464V12.6006C3.93464 12.7499 3.99379 12.8931 4.09907 12.9986C4.20435 13.1041 4.34715 13.1634 4.49604 13.1634C4.64494 13.1634 4.78773 13.1041 4.89301 12.9986C4.9983 12.8931 5.05745 12.7499 5.05745 12.6006V11.282H7.46346V12.6006C7.46346 12.7499 7.52261 12.8931 7.62789 12.9986C7.73318 13.1041 7.87597 13.1634 8.02486 13.1634C8.17376 13.1634 8.31655 13.1041 8.42184 12.9986C8.52712 12.8931 8.58627 12.7499 8.58627 12.6006V11.282H10.9923V12.6006C10.9923 12.7499 11.0514 12.8931 11.1567 12.9986C11.262 13.1041 11.4048 13.1634 11.5537 13.1634C11.7026 13.1634 11.8454 13.1041 11.9507 12.9986C12.0559 12.8931 12.1151 12.7499 12.1151 12.6006V11.282H13.7191C13.868 11.282 14.0108 11.2227 14.1161 11.1172C14.2214 11.0116 14.2805 10.8685 14.2805 10.7192C14.2805 10.57 14.2214 10.4268 14.1161 10.3213C14.0108 10.2157 13.868 10.1564 13.7191 10.1564H12.1151V8.84425C12.1151 8.69498 12.0559 8.55183 11.9507 8.44628C11.8454 8.34073 11.7026 8.28143 11.5537 8.28143C11.4048 8.28143 11.262 8.34073 11.1567 8.44628C11.0514 8.55183 10.9923 8.69498 10.9923 8.84425V10.1628H8.58627V8.84425C8.58627 8.69498 8.52712 8.55183 8.42184 8.44628C8.31655 8.34073 8.17376 8.28143 8.02486 8.28143C7.87597 8.28143 7.73318 8.34073 7.62789 8.44628C7.52261 8.55183 7.46346 8.69498 7.46346 8.84425V10.1628H5.05745V8.84425C5.05745 8.69498 4.9983 8.55183 4.89301 8.44628C4.78773 8.34073 4.64494 8.28143 4.49604 8.28143C4.34715 8.28143 4.20435 8.34073 4.09907 8.44628C3.99379 8.55183 3.93464 8.69498 3.93464 8.84425V10.1628H2.33063C2.18174 10.1628 2.03894 10.2221 1.93366 10.3277C1.82837 10.4332 1.76923 10.5764 1.76923 10.7257C1.76923 10.8749 1.82837 11.0181 1.93366 11.1236C2.03894 11.2292 2.18174 11.2885 2.33063 11.2885V11.282Z' fill='%23167CAC'/%3E%3C/svg%3E"; \ No newline at end of file +$svg-shop-list-button-green-availability: "data:image/svg+xml,%3Csvg viewBox='0 0 13 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.5 12C3.19159 12 0.5 9.30841 0.5 6C0.5 2.69159 3.19159 0 6.5 0C9.80841 0 12.5 2.69159 12.5 6C12.5 9.30841 9.80841 12 6.5 12ZM6.5 0.785047C3.62449 0.785047 1.28505 3.12449 1.28505 6C1.28505 8.87551 3.62449 11.215 6.5 11.215C9.37551 11.215 11.715 8.87551 11.715 6C11.715 3.12449 9.37551 0.785047 6.5 0.785047Z' fill='%23006A36'/%3E%3Cpath d='M5.697 7.95252C5.5927 7.95252 5.49289 7.91102 5.41999 7.837L3.90597 6.32299C3.75233 6.16934 3.75233 5.92149 3.90597 5.76785C4.05962 5.6142 4.30747 5.6142 4.46111 5.76785L5.69812 7.00373L8.53999 4.16186C8.69364 4.00822 8.94149 4.00822 9.09513 4.16186C9.24878 4.31551 9.24878 4.56336 9.09513 4.717L5.97626 7.83588C5.90224 7.9099 5.80242 7.9514 5.69925 7.9514L5.697 7.95252Z' fill='%23006A36'/%3E%3C/svg%3E%0A"; +$svg-shop-list-button-orange-availability: "data:image/svg+xml,%3Csvg viewBox='0 0 13 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.5 0C9.81368 0 12.5 2.68632 12.5 6C12.5 9.31368 9.81368 12 6.5 12C3.18632 12 0.5 9.31368 0.5 6C0.5 2.68632 3.18632 0 6.5 0ZM6.5 0.84C3.6548 0.84 1.34 3.1548 1.34 6C1.34 8.8452 3.6548 11.16 6.5 11.16C9.3452 11.16 11.66 8.8452 11.66 6C11.66 3.1548 9.3452 0.84 6.5 0.84ZM7.90018 4.00596C8.06422 3.84204 8.33002 3.84192 8.49406 4.00596C8.6581 4.17 8.6581 4.43592 8.49406 4.59996L7.0939 6L8.49406 7.40004C8.6581 7.56408 8.6581 7.83 8.49406 7.99404C8.4121 8.076 8.30458 8.11704 8.19706 8.11704C8.08966 8.11704 7.98214 8.076 7.90018 7.99404L6.50002 6.594L5.09986 7.99404C5.01778 8.076 4.91038 8.11704 4.80286 8.11704C4.69546 8.11704 4.58794 8.076 4.50598 7.99404C4.34182 7.83 4.34182 7.56408 4.50598 7.40004L5.90614 6L4.50598 4.59996C4.34182 4.43592 4.34182 4.17 4.50598 4.00596C4.66978 3.84192 4.93582 3.84204 5.09986 4.00596L6.50002 5.406L7.90018 4.00596Z' fill='%23E86421'/%3E%3C/svg%3E%0A"; +$svg-update-zip-text-link: "data:image/svg+xml,%3Csvg viewBox='0 0 13 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.49635 1.00142e-07C5.64734 -0.000153295 4.80722 0.175918 4.0274 0.517444C3.24757 0.858969 2.54443 1.35877 1.96099 1.98626C0.765713 3.27588 0.0999756 4.98141 0.0999756 6.75394C0.0999756 8.52646 0.765713 10.232 1.96099 11.5216L5.98324 15.777C6.04954 15.8475 6.12918 15.9036 6.21736 15.9419C6.30555 15.9802 6.40045 16 6.49635 16C6.59225 16 6.68716 15.9802 6.77534 15.9419C6.86353 15.9036 6.94317 15.8475 7.00946 15.777L11.0317 11.52C12.2391 10.2383 12.909 8.52914 12.8999 6.75394C12.9094 4.97818 12.2394 3.26832 11.0317 1.98626C10.4481 1.35899 9.74493 0.859347 8.96514 0.517839C8.18535 0.176331 7.34532 0.000130509 6.49635 1.00142e-07V1.00142e-07ZM6.49635 9.13131C6.02507 9.13131 5.56437 8.98913 5.17251 8.72275C4.78065 8.45637 4.47524 8.07776 4.29488 7.63479C4.11453 7.19181 4.06734 6.70438 4.15928 6.23412C4.25123 5.76387 4.47817 5.33191 4.81142 4.99287C5.14467 4.65384 5.56925 4.42295 6.03148 4.32941C6.49371 4.23587 6.97282 4.28388 7.40823 4.46736C7.84364 4.65085 8.21579 4.96157 8.47762 5.36023C8.73945 5.7589 8.87921 6.2276 8.87921 6.70707C8.87921 7.34974 8.62837 7.96611 8.18185 8.4207C7.73532 8.87528 7.12964 9.13088 6.49794 9.13131H6.49635Z' fill='%231574A1'/%3E%3C/svg%3E%0A"; \ No newline at end of file From a37d55a30680dda09b779479971a7d031ff558cb Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Thu, 18 Jan 2024 14:31:29 -0500 Subject: [PATCH 470/674] remove old review-page --- src/layouts/payment-method/payment-method.vue | 2 +- .../review-block/review-block.spec.js | 44 - .../review-page/review-block/review-block.vue | 73 -- src/layouts/review-page/review-page.spec.js | 386 ------- src/layouts/review-page/review-page.vue | 320 ------ .../customer-review/customer-review.spec.js | 129 --- .../customer-review/customer-review.vue | 51 - .../damage-review/damage-review.spec.js | 436 -------- .../damage-review/damage-review.vue | 134 --- .../schedule-review/schedule-review.vue | 42 - .../service-location-review.spec.js | 134 --- .../service-location-review.vue | 59 -- .../service-package-review.spec.js | 969 ------------------ .../service-package-review.vue | 141 --- .../vehicle-review/vehicle-review.spec.js | 47 - .../vehicle-review/vehicle-review.vue | 36 - .../service-packages/service-packages.vue | 4 +- src/router/router-constants/issPage-values.js | 2 +- src/router/router-constants/routing-table.js | 30 +- 19 files changed, 7 insertions(+), 3032 deletions(-) delete mode 100644 src/layouts/review-page/review-block/review-block.spec.js delete mode 100644 src/layouts/review-page/review-block/review-block.vue delete mode 100644 src/layouts/review-page/review-page.spec.js delete mode 100644 src/layouts/review-page/review-page.vue delete mode 100644 src/layouts/review-page/review-sections/customer-review/customer-review.spec.js delete mode 100644 src/layouts/review-page/review-sections/customer-review/customer-review.vue delete mode 100644 src/layouts/review-page/review-sections/damage-review/damage-review.spec.js delete mode 100644 src/layouts/review-page/review-sections/damage-review/damage-review.vue delete mode 100644 src/layouts/review-page/review-sections/schedule-review/schedule-review.vue delete mode 100644 src/layouts/review-page/review-sections/service-location-review/service-location-review.spec.js delete mode 100644 src/layouts/review-page/review-sections/service-location-review/service-location-review.vue delete mode 100644 src/layouts/review-page/review-sections/service-package-review/service-package-review.spec.js delete mode 100644 src/layouts/review-page/review-sections/service-package-review/service-package-review.vue delete mode 100644 src/layouts/review-page/review-sections/vehicle-review/vehicle-review.spec.js delete mode 100644 src/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index ba28cea7..5619018c 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -29,7 +29,7 @@ :isForwardActionDisabled="!meta.valid" :isBackButtonHidden="shouldHideBackButton" buttonSize - @backClicked="backButtonAction" + @backClicked="navigateBack" @ForwardClicked="forwardButtonAction" />
diff --git a/src/layouts/review-page/review-block/review-block.spec.js b/src/layouts/review-page/review-block/review-block.spec.js deleted file mode 100644 index 738a7df2..00000000 --- a/src/layouts/review-page/review-block/review-block.spec.js +++ /dev/null @@ -1,44 +0,0 @@ -// Components -import reviewBlock from '@/layouts/review-page/review-block/review-block.vue'; - -// Supporting Files -import { shallowMount } from '@vue/test-utils'; -import { getMountOptions } from '@/helpers/unit-test-helper.js'; - -// Mock fetchCmsContentForPage -jest.mock('@/helpers/cms-content-helper', () => ({ - fetchCmsContentForPage: jest.fn() -})); - -function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { - const mountOptions = getMountOptions({ - router: { - navigate: jest.fn() - } - }); - - methodToRun(); - - mountOptions.data = () => ( - initialData - ); - - const wrapper = shallowMount(reviewBlock, mountOptions); - return { wrapper }; -} - -describe('Review Content Block', () => { - test('Displays one new line of content for each element in the content prop.', () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - headerCmsWidgetName: 'TestWidget', - content: ['a', 'b', 'c', 'd'] - }); - - // Act - const contentLines = wrapper.findAll("[data-test='contentLine']"); - - // Assert - expect(contentLines.length).toBe(4); - }); -}); diff --git a/src/layouts/review-page/review-block/review-block.vue b/src/layouts/review-page/review-block/review-block.vue deleted file mode 100644 index 73792be1..00000000 --- a/src/layouts/review-page/review-block/review-block.vue +++ /dev/null @@ -1,73 +0,0 @@ - - - - - diff --git a/src/layouts/review-page/review-page.spec.js b/src/layouts/review-page/review-page.spec.js deleted file mode 100644 index a9739cef..00000000 --- a/src/layouts/review-page/review-page.spec.js +++ /dev/null @@ -1,386 +0,0 @@ -// Components -import review from '@/layouts/review-page/review-page.vue'; - -// Supporting Files -import { createTestingPinia } from '@pinia/testing'; -import { shallowMount } from '@vue/test-utils'; -import { getMountOptions } from '@/helpers/unit-test-helper.js'; -import { useMainStore } from '@/store/index.js'; - -// Mock fetchCmsContentForPage -jest.mock('@/helpers/cms-content-helper', () => ({ - fetchCmsContentForPage: jest.fn() -})); - -const mockMixin = { - methods: { - getCmsContent: jest.fn().mockImplementation(() => ''), - setCmsContent: jest.fn() - } -}; - -const footerStub = { - render: () => {}, - methods: { - updateButtonText: jest.fn() - } -}; - -const loadingModalStub = { - render: () => {}, - methods: { - showModal: jest.fn(), - hideModal: jest.fn() - } -}; - -function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { - const mountOptions = getMountOptions({ - router: { - navigate: jest.fn() - } - }); - - // mountOptions.global.mocks["$store"] = store; - - mountOptions.global.stubs = { - siteFooter: footerStub, - loadingModal: loadingModalStub - }; - - methodToRun(); - - mountOptions.mixins = [mockMixin]; - mountOptions.data = () => ( - initialData - ); - - const wrapper = shallowMount(review, mountOptions); - return { wrapper }; -} - -beforeEach(() => { - const testingPinia = createTestingPinia({ - initialState: { - main: { - order: { - vehicle: { - year: '2020', - make: 'Acura', - model: 'MDX', - style: '4 door sedan' - }, - damage: { - isRepair: false, - numberOfChips: 2, - glassToReplace: ['dummy location value'] - }, - lineItems: { - glassParts: ['dummy part value'], - supportingItems: ['dummy supporting item'], - vaps: ['dummy vap'] - }, - serviceLocation: { - address: 'address 1', - address2: 'address 2', - city: 'city', - state: 'state', - zipCode: 'zip code', - appointmentType: 'Mobile', - provider: { - providerNumber: 1, - address: { - streetAddress: 'provider address 1', - city: 'provider city', - state: 'provider state', - zipCode: 'provider zip code' - } - } - }, - schedule: { - date: 'date', - startTime: 'start', - endTime: 'end', - jobMinMinutes: '30', - jobMaxMinutes: '45' - }, - customer: { - firstName: 'first name', - lastName: 'last name', - emailAddress: 'builddigitaltest@safelite.com', - phoneNumber: '555-555-5555', - isSmsOptIn: true - } - } - } - } - }); - useMainStore(testingPinia); -}); -afterEach(() => { - jest.clearAllMocks(); -}); - -describe('Review Page', () => { - describe('arePagePrerequisitesValid', () => { - test('Returns true for baseline valid state', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test('Returns false for empty state', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order = { - vehicle: { - year: null, - make: null, - model: null, - style: null, - carId: null, - category: null, - vin: null, - imageUrl: null, - imageVifNumber: null, - imageColor: null, - registration: { - licensePlate: null - } - }, - serviceLocation: { - address: null, - address2: null, - city: null, - state: null, - zipCode: null, - zipCodeCtu: null, - appointmentType: null, - isVehicleProtected: null, - provider: { - providerNumber: null, - address: { - streetAddress: null, - city: null, - state: null, - zipCode: null, - zipCodeCtu: null - } - }, - techNotes: null - }, - customer: { - firstName: null, - lastName: null, - emailAddress: null, - phoneNumber: null, - isSmsOptIn: null - }, - damage: { - isRepair: null, - numberOfChips: null, - glassToReplace: null, - partQuestionAnswers: null, - moldingQuestionAnswers: null, - capabilityQuestionAnswers: null - }, - lineItems: { - glassParts: null, - supportingItems: null, - vaps: null, - serverData: null - }, - payment: { - isInsurance: null, - insuranceCoverage: { - isVerified: null, - coverageStatus: null - }, - parentAccountNumber: 0 - }, - schedule: { - date: null, - startTime: null, - endTime: null, - routeCode: null, - jobMaxMinutes: null, - jobMinMinutes: null - }, - referralNumber: null, - referralSequenceNumber: null, - referralDate: null, - referralCorrelationId: null, - eon: null - }; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - describe('Damage requirements', () => { - test('Accepts null glassToReplace when is repair', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.damage.isRepair = true; - wrapper.vm.mainStore.order.damage.glassToReplace = null; - wrapper.vm.mainStore.order.damage.numberOfChips = 1; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test('Rejects 0 chips when repair', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.damage.isRepair = true; - wrapper.vm.mainStore.order.damage.numberOfChips = 0; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - test('Rejects null chips when repair', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.damage.isRepair = true; - wrapper.vm.mainStore.order.damage.numberOfChips = null; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - test('Accepts null chips when not repair', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.damage.isRepair = false; - wrapper.vm.mainStore.order.damage.numberOfChips = null; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test('Rejects empty glassToReplace when not repair', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.damage.isRepair = false; - wrapper.vm.mainStore.order.damage.glassToReplace = null; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - test('Rejects null glassToReplace when not repair', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.damage.isRepair = false; - wrapper.vm.mainStore.order.damage.glassToReplace = []; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - }); - describe('Package requirements', () => { - test('Accepts null glassParts when is repair', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.damage.isRepair = true; - wrapper.vm.mainStore.order.lineItems.glassParts = null; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test('Rejects null glassParts when not repair', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.damage.isRepair = false; - wrapper.vm.mainStore.order.lineItems.glassParts = null; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - }); - describe('Service Location requirements', () => { - test('Accepts null provider address when mobile appointment', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = 'Mobile'; - wrapper.vm.mainStore.order.serviceLocation.provider.address = {}; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test('Reject null provider address when non-mobile appointment', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = 'Inshop'; - wrapper.vm.mainStore.order.serviceLocation.provider.address = {}; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - test('Accepts null service location address when non-mobile appointment', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = 'Inshop'; - wrapper.vm.mainStore.order.serviceLocation.address = null; - wrapper.vm.mainStore.order.serviceLocation.address2 = null; - wrapper.vm.mainStore.order.serviceLocation.zipCode = null; - wrapper.vm.mainStore.order.serviceLocation.city = null; - wrapper.vm.mainStore.order.serviceLocation.state = null; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(true); - }); - test('Rejects null service location address when mobile appointment', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = 'Mobile'; - wrapper.vm.mainStore.order.serviceLocation.address = null; - wrapper.vm.mainStore.order.serviceLocation.address2 = null; - wrapper.vm.mainStore.order.serviceLocation.zipCode = null; - wrapper.vm.mainStore.order.serviceLocation.city = null; - wrapper.vm.mainStore.order.serviceLocation.state = null; - - // Act - const isValid = wrapper.vm.arePagePrerequisitesValid(); - - // Assert - expect(isValid).toBe(false); - }); - }); - }); -}); diff --git a/src/layouts/review-page/review-page.vue b/src/layouts/review-page/review-page.vue deleted file mode 100644 index 36fcb749..00000000 --- a/src/layouts/review-page/review-page.vue +++ /dev/null @@ -1,320 +0,0 @@ - - - - - diff --git a/src/layouts/review-page/review-sections/customer-review/customer-review.spec.js b/src/layouts/review-page/review-sections/customer-review/customer-review.spec.js deleted file mode 100644 index 1e0f612d..00000000 --- a/src/layouts/review-page/review-sections/customer-review/customer-review.spec.js +++ /dev/null @@ -1,129 +0,0 @@ -// Components -import customerReview from '@/layouts/review-page/review-sections/customer-review/customer-review.vue'; - -// Supporting Files -import { shallowMount } from '@vue/test-utils'; -import { getMountOptions } from '@/helpers/unit-test-helper.js'; - -const testConstants = { - cms: { - header: { - text: 'Header' - }, - sms: { - text: 'Sms' - } - }, - customer: { - firstName: 'First', - lastName: 'Last', - phoneNumber: '111-111-1111', - emailAddress: 'builddigitaltest@safelite.com', - isSmsOptIn: false - }, - displayContent: { - fullName: 'First Last', - phoneNumber: '111-111-1111', - emailAddress: 'builddigitaltest@safelite.com', - smsOptIn: 'Sms' - } -}; - -function generateDefaultProps() { - return { - cmsWidgetName: 'CustomerWidget', - customer: { - firstName: testConstants.customer.firstName, - lastName: testConstants.customer.lastName, - phoneNumber: testConstants.customer.phoneNumber, - emailAddress: testConstants.customer.emailAddress, - isSmsOptIn: testConstants.customer.isSmsOptIn - } - }; -} - -let cmsContent; -const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '') - } -}; - -function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { - const mountOptions = getMountOptions({ - router: { - navigate: jest.fn() - } - }); - - methodToRun(); - - mountOptions.data = () => ( - initialData - ); - - mountOptions.mixins = [mockMixin]; - - const wrapper = shallowMount(customerReview, mountOptions); - return { wrapper }; -} - -beforeEach(() => { - cmsContent = { - CustomerWidget: { - HeaderText: testConstants.cms.header.text, - SubheaderText: testConstants.cms.sms.text - } - }; -}); - -describe('Customer Review Block', () => { - test('Should display header text from cms', async () => { - // Arrange - const props = generateDefaultProps(); - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.header).toEqual(testConstants.cms.header.text); - }); - - test('Should display sms text from cms', async () => { - // Arrange - const props = generateDefaultProps(); - - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.text); - }); - - test('Should render correct display content', async () => { - // Arrange - const props = generateDefaultProps(); - - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toEqual([ - testConstants.displayContent.fullName, - testConstants.displayContent.emailAddress, - testConstants.displayContent.phoneNumber, - testConstants.displayContent.smsOptIn - ]); - }); -}); diff --git a/src/layouts/review-page/review-sections/customer-review/customer-review.vue b/src/layouts/review-page/review-sections/customer-review/customer-review.vue deleted file mode 100644 index 5f442531..00000000 --- a/src/layouts/review-page/review-sections/customer-review/customer-review.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - diff --git a/src/layouts/review-page/review-sections/damage-review/damage-review.spec.js b/src/layouts/review-page/review-sections/damage-review/damage-review.spec.js deleted file mode 100644 index b7a36442..00000000 --- a/src/layouts/review-page/review-sections/damage-review/damage-review.spec.js +++ /dev/null @@ -1,436 +0,0 @@ -// Components -import damageReview from '@/layouts/review-page/review-sections/damage-review/damage-review.vue'; - -// Supporting Files -import { shallowMount } from '@vue/test-utils'; -import { getMountOptions } from '@/helpers/unit-test-helper.js'; -import damageLocationsSelected from '@/constants/damage-locations-selected'; - -const testConstants = { - cmsConstants: { - widgetNames: { - header: 'DamageReviewWidget', - locations: 'DamageLocationsWidget', - driverDamages: 'DriverDamagesWidget', - passengerDamages: 'PassengerDamagesWidget' - }, - header: { - text: 'Damage' - }, - damageLocations: { - windshield: damageLocationsSelected.WINDSHIELD, - driver: damageLocationsSelected.DRIVER, - passenger: damageLocationsSelected.PASSENGER, - rear: damageLocationsSelected.REAR - }, - damageNames: { - vent: damageLocationsSelected.VENT, - front: damageLocationsSelected.FRONT, - back: damageLocationsSelected.BACK, - quarter: damageLocationsSelected.QUARTER, - side: damageLocationsSelected.SIDEDOOR - }, - locationCopy: { - windshield: 'Windshield copy', - driver: 'Driver copy', - passenger: 'Passenger copy', - rear: 'Rear copy' - }, - damageCopy: { - vent: 'Vent copy', - front: 'Front copy', - back: 'Back copy', - quarter: 'Quarter copy', - side: 'Side copy' - }, - imageId: '00000000-0000-0000-0000-000000000000' - }, - makeBulletedList: (items) => { - let list = '
    '; - items.forEach((item) => { - list += `
  • ${item}
  • `; - }); - list += '
'; - - return list; - }, - glassItems: { - windshield: { - glassLocation: damageLocationsSelected.WINDSHIELD, - glassName: damageLocationsSelected.SINGLE - }, - rear: { - glassLocation: damageLocationsSelected.REAR, - glassName: damageLocationsSelected.STATIONARY - }, - passengerItems: { - vent: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.VENT - }, - front: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.FRONT - }, - back: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.BACK - }, - quarter: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.QUARTER - }, - side: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.SIDEDOOR - } - }, - driverItems: { - vent: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.VENT - }, - front: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.FRONT - }, - back: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.BACK - }, - quarter: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.QUARTER - }, - side: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.SIDEDOOR - } - } - } -}; - -let cmsContent; -const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '') - } -}; - -function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { - const mountOptions = getMountOptions({ - router: { - navigate: jest.fn() - } - }); - - methodToRun(); - - mountOptions.data = () => ( - initialData - ); - - mountOptions.mixins = [mockMixin]; - - const wrapper = shallowMount(damageReview, mountOptions); - return { wrapper }; -} - -beforeEach(() => { - cmsContent = { - DamageReviewWidget: { - Text: testConstants.cmsConstants.header.text - }, - DamageLocationsWidget: { - Answers: [ - { - Name: testConstants.cmsConstants.damageLocations.windshield, - Text: testConstants.cmsConstants.locationCopy.windshield, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageLocations.driver, - Text: testConstants.cmsConstants.locationCopy.driver, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: testConstants.cmsConstants.widgetNames.driverDamages - }, - { - Name: testConstants.cmsConstants.damageLocations.passenger, - Text: testConstants.cmsConstants.locationCopy.passenger, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: testConstants.cmsConstants.widgetNames.passengerDamages - }, - { - Name: testConstants.cmsConstants.damageLocations.rear, - Text: testConstants.cmsConstants.locationCopy.rear, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - } - ] - }, - DriverDamagesWidget: { - Answers: [ - { - Name: testConstants.cmsConstants.damageNames.vent, - Text: testConstants.cmsConstants.damageCopy.vent, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.front, - Text: testConstants.cmsConstants.damageCopy.front, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.back, - Text: testConstants.cmsConstants.damageCopy.back, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.quarter, - Text: testConstants.cmsConstants.damageCopy.quarter, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.side, - Text: testConstants.cmsConstants.damageCopy.side, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - } - ] - }, - PassengerDamagesWidget: { - Answers: [ - { - Name: testConstants.cmsConstants.damageNames.vent, - Text: testConstants.cmsConstants.damageCopy.vent, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.front, - Text: testConstants.cmsConstants.damageCopy.front, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.back, - Text: testConstants.cmsConstants.damageCopy.back, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.quarter, - Text: testConstants.cmsConstants.damageCopy.quarter, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.side, - Text: testConstants.cmsConstants.damageCopy.side, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - } - ] - } - }; -}); - -describe('Damage Review Block', () => { - describe('Correctly assembles damage info into a display string', () => { - test('Shows windshield copy when windshield damage is included', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - glassToReplace: [testConstants.glassItems.windshield] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.windshield - ]); - }); - - test('Windshield copy is shown when order is a repair', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: true, - numberOfChips: 2, - glassToReplace: [] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.windshield - ]); - }); - - test('Rear windshield copy shows when rear damage is present', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - numberOfChips: null, - glassToReplace: [testConstants.glassItems.rear] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.rear - ]); - }); - - test('Driver side copy and items are shown when driver side damage is present', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - numberOfChips: null, - glassToReplace: [ - testConstants.glassItems.driverItems.back, - testConstants.glassItems.driverItems.front - ] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.driver, - testConstants.makeBulletedList([ - testConstants.cmsConstants.damageCopy.front, - testConstants.cmsConstants.damageCopy.back - ]) - ]); - }); - - test('Passenger side copy and items are shown when passenger side damage is present', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - numberOfChips: null, - glassToReplace: [ - testConstants.glassItems.passengerItems.quarter, - testConstants.glassItems.passengerItems.vent, - testConstants.glassItems.passengerItems.side - ] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.passenger, - testConstants.makeBulletedList([ - testConstants.cmsConstants.damageCopy.vent, - testConstants.cmsConstants.damageCopy.quarter, - testConstants.cmsConstants.damageCopy.side - ]) - ]); - }); - - test('All relevant sections are shown in order in multiglass scenario', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - numberOfChips: null, - glassToReplace: [ - testConstants.glassItems.windshield, - testConstants.glassItems.rear, - testConstants.glassItems.driverItems.vent, - testConstants.glassItems.driverItems.front, - testConstants.glassItems.driverItems.back, - testConstants.glassItems.passengerItems.quarter, - testConstants.glassItems.passengerItems.back, - testConstants.glassItems.passengerItems.side - ] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.windshield, - testConstants.cmsConstants.locationCopy.driver, - testConstants.makeBulletedList([ - testConstants.cmsConstants.damageCopy.vent, - testConstants.cmsConstants.damageCopy.front, - testConstants.cmsConstants.damageCopy.back - ]), - testConstants.cmsConstants.locationCopy.passenger, - testConstants.makeBulletedList([ - testConstants.cmsConstants.damageCopy.back, - testConstants.cmsConstants.damageCopy.quarter, - testConstants.cmsConstants.damageCopy.side - ]), - testConstants.cmsConstants.locationCopy.rear - ]); - }); - }); -}); diff --git a/src/layouts/review-page/review-sections/damage-review/damage-review.vue b/src/layouts/review-page/review-sections/damage-review/damage-review.vue deleted file mode 100644 index 4e0b0878..00000000 --- a/src/layouts/review-page/review-sections/damage-review/damage-review.vue +++ /dev/null @@ -1,134 +0,0 @@ - - - diff --git a/src/layouts/review-page/review-sections/schedule-review/schedule-review.vue b/src/layouts/review-page/review-sections/schedule-review/schedule-review.vue deleted file mode 100644 index d34e33a5..00000000 --- a/src/layouts/review-page/review-sections/schedule-review/schedule-review.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/src/layouts/review-page/review-sections/service-location-review/service-location-review.spec.js b/src/layouts/review-page/review-sections/service-location-review/service-location-review.spec.js deleted file mode 100644 index 834714aa..00000000 --- a/src/layouts/review-page/review-sections/service-location-review/service-location-review.spec.js +++ /dev/null @@ -1,134 +0,0 @@ -// Components -import serviceLocationReview from '@/layouts/review-page/review-sections/service-location-review/service-location-review.vue'; - -// Supporting Files -import { shallowMount } from '@vue/test-utils'; -import { getMountOptions } from '@/helpers/unit-test-helper.js'; -import { AppointmentTypeStrings } from '@/constants/schedule-constants'; - -const cmsContent = { - ServiceLocationTitleWidget: { - Text: 'Title Text' - } -}; - -const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '') - } -}; - -function generateDefaultProps() { - return { - cmsWidgetName: 'ServiceLocationTitleWidget', - serviceLocation: { - address: 'Mobile Address 1', - address2: 'Mobile Address 2', - city: 'Mobile City', - state: 'MO', - zipCode: '11111', - zipCodeCtu: '', - appointmentType: AppointmentTypeStrings.MOBILE, - isVehicleProtected: false, - provider: { - providerNumber: '', - address: { - streetAddress: 'Service Location Address', - city: 'Service Location City', - state: 'SL', - zipCode: '22222', - zipCodeCtu: '' - } - } - } - }; -} - -function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { - const mountOptions = getMountOptions({ - router: { - navigate: jest.fn() - } - }); - - methodToRun(); - - mountOptions.data = () => ( - initialData - ); - - mountOptions.mixins = [mockMixin]; - - const wrapper = shallowMount(serviceLocationReview, mountOptions); - return { wrapper }; -} - -describe('Service Location Review Block', () => { - test('Should render mobile address if mobile appointment', async () => { - // Arrange - const props = generateDefaultProps(); - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toEqual([ - 'Mobile Address 1, Mobile Address 2, Mobile City, MO 11111' - ]); - }); - - test('Should render service location address if inshop appointment.', async () => { - // Arrange - const props = generateDefaultProps(); - props.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP; - - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toEqual([ - 'Service Location Address, Service Location City, SL 22222' - ]); - }); - - test('Should render service location address if drop-off appointment', async () => { - // Arrange - const props = generateDefaultProps(); - props.serviceLocation.appointmentType = AppointmentTypeStrings.DROP_OFF; - - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toEqual([ - 'Service Location Address, Service Location City, SL 22222' - ]); - }); - - test('Should not add comma or any text if address2 is null', async () => { - // Arrange - const props = generateDefaultProps(); - props.serviceLocation.address2 = null; - - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toEqual(['Mobile Address 1, Mobile City, MO 11111']); - }); -}); diff --git a/src/layouts/review-page/review-sections/service-location-review/service-location-review.vue b/src/layouts/review-page/review-sections/service-location-review/service-location-review.vue deleted file mode 100644 index 59241b15..00000000 --- a/src/layouts/review-page/review-sections/service-location-review/service-location-review.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/src/layouts/review-page/review-sections/service-package-review/service-package-review.spec.js b/src/layouts/review-page/review-sections/service-package-review/service-package-review.spec.js deleted file mode 100644 index 6dfd6f4e..00000000 --- a/src/layouts/review-page/review-sections/service-package-review/service-package-review.spec.js +++ /dev/null @@ -1,969 +0,0 @@ -// Components -import servicePackageReview from '@/layouts/review-page/review-sections/service-package-review/service-package-review.vue'; - -// Supporting Files -import { shallowMount } from '@vue/test-utils'; -import { getMountOptions } from '@/helpers/unit-test-helper.js'; -import packageNames from '@/constants/package-names'; -import partTypeStrings from '@/constants/part-type-strings'; -import damageLocationsSelected from '@/constants/damage-locations-selected'; - -const testConstants = { - cmsPropValues: { - servicePackageOptionsCmsName: 'ServicePackageTitle', - defaultPackageItemsCmsName: 'DefaultPackageItemDescriptions', - vapsItemsCmsName: 'VapsItemDescriptions' - }, - widgetNames: { - tierOneTitle: 'EconomyServiceTitle', - tierTwoTitle: 'StandardServiceTitle', - tierThreeTitle: 'PremiumServiceTitle' - }, - defaultItemCopy: { - itemOne: 'Item Description 1', - itemTwo: 'Item Description 2', - itemThree: 'Item Description 3', - itemFour: 'Item Description 4', - defaultItemCopyArray: ['Item Description 1', 'Item Description 2', 'Item Description 3'] - }, - vapsCopy: { - frontWiperCopy: 'Front Wiper copy', - rearWiperCopy: 'Rear Wiper copy', - rainDefenseCopy: 'Rain defense copy' - }, - parts: { - frontWiperPart: { - partNumber: 'SBB16', - description: 'SAFELITE BEAM BLADE 16', - partType: 'FRONT WIPER', - price: 32.64 - }, - rearWiperPart: { - partNumber: 'SBBR12A', - description: 'SAFELITE REAR BLADE 12A', - partType: 'REAR WIPER', - price: 24.48 - }, - rainDefensePart: { - partNumber: 'RAIN DEFENSE', - description: null, - partType: 'RAIN DEFENSE', - price: 35.5 - }, - recalPart: { - partNumber: 'RECAL STATIC', - Description: 'Recalibration', - partType: 'recalibration', - Quantity: '1', - price: 150.0 - } - }, - damages: { - frontWindshield: { - glassLocation: damageLocationsSelected.WINDSHIELD, - glassName: damageLocationsSelected.SINGLE - }, - rearWindshield: { - glassLocation: damageLocationsSelected.REAR, - glassName: damageLocationsSelected.STATIONARY - }, - sideGlass: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.QUARTER - } - }, - imageId: '00000000-0000-0000-0000-000000000000' -}; - -const figmaScenarios = [ - { - name: '05_01_CSR_Quote_Cash', - params: { - wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: false, - glassToReplace: [testConstants.damages.frontWindshield] - }, - glassParts: [], - supportingItems: [] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Standard', - vapsCombo: [testConstants.parts.frontWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy - ] - } - }, - { - name: 'Premium', - vapsCombo: [ - testConstants.parts.rainDefensePart, - testConstants.parts.frontWiperPart - ], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Standard+RearWiper', - vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rearWiperCopy - ] - } - } - ] - }, - { - name: '05_01_CSR_Quote_Standard_Repair', - params: { - wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: true, - glassToReplace: [] - }, - glassParts: [], - supportingItems: [] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Standard', - vapsCombo: [testConstants.parts.frontWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy - ] - } - }, - { - name: 'Premium', - vapsCombo: [ - testConstants.parts.rainDefensePart, - testConstants.parts.frontWiperPart - ], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Standard+RearWiper', - vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rearWiperCopy - ] - } - } - ] - }, - { - name: '05_01_CSR_Quote_Recal', - params: { - wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: false, - glassToReplace: [testConstants.damages.frontWindshield] - }, - glassParts: [], - supportingItems: [testConstants.parts.recalPart] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Standard', - vapsCombo: [testConstants.parts.frontWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy - ] - } - }, - { - name: 'Premium', - vapsCombo: [ - testConstants.parts.rainDefensePart, - testConstants.parts.frontWiperPart - ], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Standard+RearWiper', - vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rearWiperCopy - ] - } - } - ] - }, - // 05_01_CSR_Quote_RearGlass omitted as a duplicate of below. - { - name: '05_01_CSR_Quote_RearGlass+NonWindshield', - params: { - wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: false, - glassToReplace: [testConstants.damages.rearWindshield] - }, - glassParts: [], - supportingItems: [] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Economy+Frontwiper', - vapsCombo: [testConstants.parts.frontWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy - ] - } - }, - { - name: 'Standard', - vapsCombo: [testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rearWiperCopy - ] - } - }, - { - name: 'Standard+RainDefense', - vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rearWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Premium', - vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.frontWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rearWiperCopy - ] - } - } - ] - }, - { - name: '05_01_CSR_Quote_RearGlass+Windshield', - params: { - wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: false, - glassToReplace: [ - testConstants.damages.frontWindshield, - testConstants.damages.rearWindshield - ] - }, - glassParts: [], - supportingItems: [] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Economy+Frontwiper', - vapsCombo: [testConstants.parts.frontWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy - ] - } - }, - { - name: 'Economy+Rearwiper', - vapsCombo: [testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rearWiperCopy - ] - } - }, - { - name: 'Economy+RainDefense', - vapsCombo: [testConstants.parts.rainDefensePart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Economy+Frontwiper+RainDefense', - vapsCombo: [ - testConstants.parts.frontWiperPart, - testConstants.parts.rainDefensePart - ], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Economy+Rearwiper+RainDefense', - vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rearWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Standard', - vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rearWiperCopy - ] - } - }, - { - name: 'Premium', - vapsCombo: [ - testConstants.parts.rearWiperPart, - testConstants.parts.frontWiperPart, - testConstants.parts.rainDefensePart - ], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rearWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - } - ] - }, - { - name: '05_01_CSR_Quote_RearGlassNoFrontFit', - params: { - wiperResponse: [testConstants.parts.rearWiperPart], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: false, - glassToReplace: [testConstants.damages.rearWindshield] - }, - glassParts: [], - supportingItems: [] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Economy+Raindefense', - vapsCombo: [testConstants.parts.rainDefensePart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Standard', - vapsCombo: [testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rearWiperCopy - ] - } - }, - { - name: 'Premium', - vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rearWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - } - ] - }, - // 05_01_CSR_Quote_Windshield+SideGlass has identical outcomes to 05_01_CSR_Quote_Cash, but included in case that changes in the future. - { - name: '05_01_CSR_Quote_Windshield+SideGlass', - params: { - wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: false, - glassToReplace: [ - testConstants.damages.frontWindshield, - testConstants.damages.sideGlass - ] - }, - glassParts: [], - supportingItems: [] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Standard', - vapsCombo: [testConstants.parts.frontWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy - ] - } - }, - { - name: 'Premium', - vapsCombo: [ - testConstants.parts.rainDefensePart, - testConstants.parts.frontWiperPart - ], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Standard+RearWiper', - vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierTwoTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rearWiperCopy - ] - } - } - ] - }, - // Has no standard package - { - name: '05_01_CSR_Quote_SideGlass', - params: { - wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: false, - glassToReplace: [testConstants.damages.sideGlass] - }, - glassParts: [], - supportingItems: [] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Economy+Frontwiper', - vapsCombo: [testConstants.parts.frontWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy - ] - } - }, - { - name: 'Economy+RainDefense', - vapsCombo: [testConstants.parts.rainDefensePart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Economy+Rearwiper', - vapsCombo: [testConstants.parts.rearWiperPart], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rearWiperCopy - ] - } - }, - { - name: 'Premium', - vapsCombo: [ - testConstants.parts.rainDefensePart, - testConstants.parts.frontWiperPart - ], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - }, - { - name: 'Premium+Rearwiper', - vapsCombo: [ - testConstants.parts.rainDefensePart, - testConstants.parts.frontWiperPart, - testConstants.parts.rearWiperPart - ], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.frontWiperCopy, - testConstants.vapsCopy.rearWiperCopy, - testConstants.vapsCopy.rainDefenseCopy - ] - } - } - ] - }, - // Has no standard package - { - name: '05_01_CSR_Quote_NoWiperFit', - params: { - wiperResponse: [], - rainDefenseResponse: testConstants.parts.rainDefensePart, - damage: { - isRepair: false, - glassToReplace: [testConstants.damages.frontWindshield] - }, - glassParts: [], - supportingItems: [] - }, - iterations: [ - { - name: 'Economy', - vapsCombo: [], - expected: { - packageNameWidget: testConstants.widgetNames.tierOneTitle, - displayContent: testConstants.defaultItemCopy.defaultItemCopyArray - } - }, - { - name: 'Premium', - vapsCombo: [testConstants.parts.rainDefensePart], - expected: { - packageNameWidget: testConstants.widgetNames.tierThreeTitle, - displayContent: [ - ...testConstants.defaultItemCopy.defaultItemCopyArray, - testConstants.vapsCopy.rainDefenseCopy - ] - } - } - ] - } -]; - -function generateDefaultProps() { - return { - servicePackageOptionsCmsName: testConstants.cmsPropValues.servicePackageOptionsCmsName, - defaultPackageItemsCmsName: testConstants.cmsPropValues.defaultPackageItemsCmsName, - vapsItemsCmsName: testConstants.cmsPropValues.vapsItemsCmsName, - lineItems: { - glassParts: [], - supportingItems: [], - vaps: [testConstants.parts.frontWiperPart] - }, - damage: { - isRepair: false, - glassToReplace: [testConstants.damages.frontWindshield] - } - }; -} - -let cmsContent; -const mockMixin = { - methods: { - getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '') - } -}; - -function initializeWithDefault(wrapper) { - wrapper.vm.initializeComponent({ - wipers: [testConstants.parts.frontWiperPart], - rainDefense: testConstants.parts.rainDefensePart - }); -} - -function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { - const mountOptions = getMountOptions({ - router: { - navigate: jest.fn() - } - }); - - methodToRun(); - - mountOptions.data = () => ( - initialData - ); - - mountOptions.mixins = [mockMixin]; - - const wrapper = shallowMount(servicePackageReview, mountOptions); - wrapper.vm.setCmsContent = jest.fn(); - return { wrapper }; -} - -beforeEach(() => { - cmsContent = { - ServicePackageTitle: { - Answers: [ - { - Name: packageNames.TIER_ONE, - Text: '', - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: testConstants.widgetNames.tierOneTitle - }, - { - Name: packageNames.TIER_TWO, - Text: '', - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: testConstants.widgetNames.tierTwoTitle - }, - { - Name: packageNames.TIER_THREE, - Text: '', - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: testConstants.widgetNames.tierThreeTitle - } - ] - }, - DefaultPackageItemDescriptions: { - Answers: [ - { - Name: 'Item1', - Text: testConstants.defaultItemCopy.itemOne, - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: 'Item2', - Text: testConstants.defaultItemCopy.itemTwo, - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: 'Item3', - Text: testConstants.defaultItemCopy.itemThree, - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: '' - } - ] - }, - VapsItemDescriptions: { - Answers: [ - { - Name: partTypeStrings.FRONT_WIPER, - Text: testConstants.vapsCopy.frontWiperCopy, - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: partTypeStrings.REAR_WIPER, - Text: testConstants.vapsCopy.rearWiperCopy, - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: partTypeStrings.RAIN_DEFENSE, - Text: testConstants.vapsCopy.rainDefenseCopy, - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: '' - } - ] - } - }; -}); - -describe('Service Package Review Block', () => { - describe('General functionality', () => { - test('Should properly "Round Down" package tier', async () => { - // Slightly longer explanation: - // Should only return the highest tier where *every* offered VAP is part of the order. - // However, there may be vaps not offered in the qualifying tier. Hence rounding *down*. - // - // I.e. Economy=[], Standard=[front wipers], Premium=[front wipers, rain defense]. - // Current vaps=[rain defense]. Though rain defense is in Premium, we don't satisfy it or standard. - // So our tier should still be Economy. - // Should still display extra vaps. - - // Arrange - const props = generateDefaultProps(); - props.lineItems.vaps = [testConstants.parts.rainDefensePart]; - - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - initializeWithDefault(wrapper); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.packageNameWidget).toEqual(testConstants.widgetNames.tierOneTitle); - - const containsRainDefenseCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.rainDefenseCopy); - expect(containsRainDefenseCopy).toBe(true); - }); - - test('Should display all default items from cms', async () => { - // Arrange - cmsContent.DefaultPackageItemDescriptions.Answers.push({ - Name: 'Item4', - Text: testConstants.defaultItemCopy.itemFour, - SubText: '', - ImageId: testConstants.imageId, - Image: '', - SubWidgetName: '' - }); - - const props = generateDefaultProps(); - props.lineItems.vaps = []; - - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - initializeWithDefault(wrapper); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - const expectedResult = [ - testConstants.defaultItemCopy.itemOne, - testConstants.defaultItemCopy.itemTwo, - testConstants.defaultItemCopy.itemThree, - testConstants.defaultItemCopy.itemFour - ]; - - expect(wrapper.vm.displayContent).toEqual(expectedResult); - }); - - test('Should display vaps if and only if they are added', async () => { - // Arrange - const props = generateDefaultProps(); - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - // Act - await wrapper.vm.$nextTick(); - - initializeWithDefault(wrapper); - - // Assert - const includesFrontWiperCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.frontWiperCopy); - const includesRainDefenseCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.rainDefenseCopy); - expect(includesFrontWiperCopy).toBe(true); - expect(includesRainDefenseCopy).toBe(false); - }); - - test('Should not error if cms content is missing (though may display poorly).', async () => { - // Arrange - cmsContent = {}; - const props = generateDefaultProps(); - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - initializeWithDefault(wrapper); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.packageNameWidget).toEqual(''); - expect(wrapper.vm.displayContent).toEqual([]); - }); - }); - - describe('Match Figma Scenarios', () => { - figmaScenarios.forEach((scenario) => { - scenario.iterations.forEach((iteration) => { - it(`Should match figma scenario "${scenario.name}", iteration "${iteration.name}"`, async () => { - // Arrange - const props = generateDefaultProps(); - props.damage = scenario.params.damage; - props.glassParts = scenario.params.glassParts; - props.lineItems.supportingItems = scenario.params.supportingItems; - props.lineItems.vaps = iteration.vapsCombo; - - const { wrapper } = getShallowMountedComponent({ - ...props - }); - - wrapper.vm.initializeComponent({ - wipers: scenario.params.wiperResponse, - rainDefense: scenario.params.rainDefenseResponse - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.packageNameWidget).toEqual(iteration.expected.packageNameWidget); - expect(wrapper.vm.displayContent).toEqual(iteration.expected.displayContent); - }); - }); - }); - }); -}); diff --git a/src/layouts/review-page/review-sections/service-package-review/service-package-review.vue b/src/layouts/review-page/review-sections/service-package-review/service-package-review.vue deleted file mode 100644 index 56655945..00000000 --- a/src/layouts/review-page/review-sections/service-package-review/service-package-review.vue +++ /dev/null @@ -1,141 +0,0 @@ - - - diff --git a/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.spec.js b/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.spec.js deleted file mode 100644 index fd4a3d64..00000000 --- a/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.spec.js +++ /dev/null @@ -1,47 +0,0 @@ -// Components -import vehicleReview from '@/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue'; - -// Supporting Files -import { shallowMount } from '@vue/test-utils'; -import { getMountOptions } from '@/helpers/unit-test-helper.js'; - -jest.mock('@/helpers/cms-content-helper', () => ({ - fetchCmsContentForPage: () => Promise.resolve('content') -})); - -function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { - const mountOptions = getMountOptions({ - router: { - navigate: jest.fn() - } - }); - - methodToRun(); - - mountOptions.data = () => ( - initialData - ); - - const wrapper = shallowMount(vehicleReview, mountOptions); - wrapper.vm.setCmsContent = jest.fn(); - return { wrapper }; -} - -describe('Vehicle Review Block', () => { - test('Correctly assembles vehicle info into a display string', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - vehicle: { - year: '2019', - make: 'Honda', - model: 'Odyssey' - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual(['2019 Honda Odyssey']); - }); -}); diff --git a/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue b/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue deleted file mode 100644 index cfc9ee09..00000000 --- a/src/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/src/layouts/service-packages/service-packages.vue b/src/layouts/service-packages/service-packages.vue index 862e1496..8644ad85 100644 --- a/src/layouts/service-packages/service-packages.vue +++ b/src/layouts/service-packages/service-packages.vue @@ -66,8 +66,8 @@ import allGlassPartsAndItemsHavePrices from '@/layouts/service-packages/service- import globalRules from '@/constants/global-rules'; import servicePackageQuestion from '@/layouts/service-packages/service-package-question/service-package-question.vue'; import issPageValues from '@/router/router-constants/issPage-values'; -import bailoutCode from "@/constants/bailoutCode"; -import bailoutMessage from "@/constants/bailoutMessage"; +import bailoutCode from '@/constants/bailoutCode'; +import bailoutMessage from '@/constants/bailoutMessage'; const store = useMainStore(); diff --git a/src/router/router-constants/issPage-values.js b/src/router/router-constants/issPage-values.js index 80b71050..419d44f3 100644 --- a/src/router/router-constants/issPage-values.js +++ b/src/router/router-constants/issPage-values.js @@ -16,11 +16,11 @@ const issPageValues = Object.freeze({ LICENSE_PLATE_LOOKUP: 'license-plate-lookup', MOLDING_QUESTIONS: 'molding-questions', ORDER_CONFIRMATION: 'order-confirmation', + PAYMENT_METHOD: 'payment-method', PAYMENT_PAGE: 'payment-page', PART_QUESTIONS: 'part-questions', POLICY_HOLDER_DETAILS: 'policy-holder-details', PROVIDER_PREFERENCE: 'provider-preference', - REVIEW_PAGE: 'review-page', REVEAL: 'reveal', SERVICE_LOCATION: 'service-location', TPA_CONFIRMATION: 'tpa-confirmation', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 2cded6f6..43371dbe 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -599,12 +599,12 @@ const routingTable = () => [ }, { scenario: navigationScenarios.CLICKED_FORWARD, - destinationIssPageValue: issPageValues.REVIEW_PAGE + destinationIssPageValue: issPageValues.PAYMENT_METHOD } ] }, { - issPageValue: issPageValues.REVIEW_PAGE, + issPageValue: issPageValues.PAYMENT_METHOD, maps: [ { scenario: navigationScenarios.CLICKED_BACK, @@ -612,31 +612,7 @@ const routingTable = () => [ }, { scenario: navigationScenarios.CLICKED_FORWARD, - destinationIssPageValue: issPageValues.PAYMENT_PAGE - }, - { - scenario: navigationScenarios.CLICKED_CUSTOMER_EDIT, - destinationIssPageValue: issPageValues.CONTACT_DETAILS - }, - { - scenario: navigationScenarios.CLICKED_DAMAGE_EDIT, - destinationIssPageValue: issPageValues.VEHICLE_DAMAGE - }, - { - scenario: navigationScenarios.CLICKED_SCHEDULE_EDIT, - destinationIssPageValue: issPageValues.SCHEDULE_PAGE - }, - { - scenario: navigationScenarios.CLICKED_SERVICE_LOCATION_EDIT, - destinationIssPageValue: issPageValues.SERVICE_LOCATION - }, - { - scenario: navigationScenarios.CLICKED_SERVICE_PACKAGE_EDIT, - destinationIssPageValue: issPageValues.SERVICE_PACKAGES - }, - { - scenario: navigationScenarios.CLICKED_VEHICLE_EDIT, - destinationIssPageValue: issPageValues.VEHICLE_SELECTION + destinationIssPageValue: issPageValues.ORDER_CONFIRMATION } ] }, From c9a262bac1edbacad24bf2ba18d33f80ceb48feb Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Thu, 18 Jan 2024 14:36:28 -0500 Subject: [PATCH 471/674] remove console.logs (except forwardButtonAction) uncomment out data load --- src/layouts/payment-method/payment-method.vue | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 5619018c..a7ca3dba 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -85,11 +85,9 @@ export default { const resultMap = await settleAllPromises(promiseResultMap); next((vm) => { - console.log('resultMap...'); - console.log(resultMap); vm.setCmsContent(resultMap.cmsContent); - // vm.$refs.reviewDropdown.initializeComponent(resultMap.reviewDropdownData); + vm.$refs.reviewDropdown.initializeComponent(resultMap.reviewDropdownData); }); }, data() { @@ -169,10 +167,8 @@ export default { && customerReqs ); }, - backButtonAction() { - console.log('back button hit...'); - }, async forwardButtonAction() { + // Multiple paths based on payment console.log('forward button hit...'); } } From 4652c68680b3a376d93ad056b29b2b673f6f312d Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Thu, 18 Jan 2024 15:32:56 -0500 Subject: [PATCH 472/674] updates for tests --- .../review-sections/customer-review/customer-review.spec.js | 2 +- .../review-sections/damage-review/damage-review.spec.js | 2 +- .../service-location-review/service-location-review.spec.js | 3 ++- .../service-package-review/service-package-review.spec.js | 3 ++- .../service-package-review/service-package-review.vue | 6 ++---- .../review-sections/vehicle-review/vehicle-review.spec.js | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js index 1e0f612d..7d523f9d 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js +++ b/src/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.spec.js @@ -1,5 +1,5 @@ // Components -import customerReview from '@/layouts/review-page/review-sections/customer-review/customer-review.vue'; +import customerReview from '@/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.vue'; // Supporting Files import { shallowMount } from '@vue/test-utils'; diff --git a/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js index b7a36442..4a0a2fa7 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js +++ b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js @@ -1,5 +1,5 @@ // Components -import damageReview from '@/layouts/review-page/review-sections/damage-review/damage-review.vue'; +import damageReview from '@/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue'; // Supporting Files import { shallowMount } from '@vue/test-utils'; diff --git a/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.spec.js index 834714aa..2f4be3b1 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.spec.js +++ b/src/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.spec.js @@ -1,5 +1,6 @@ // Components -import serviceLocationReview from '@/layouts/review-page/review-sections/service-location-review/service-location-review.vue'; +import +serviceLocationReview from '@/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.vue'; // Supporting Files import { shallowMount } from '@vue/test-utils'; diff --git a/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.spec.js index 6dfd6f4e..500c9bac 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.spec.js +++ b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.spec.js @@ -1,5 +1,6 @@ // Components -import servicePackageReview from '@/layouts/review-page/review-sections/service-package-review/service-package-review.vue'; +import +servicePackageReview from '@/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue'; // Supporting Files import { shallowMount } from '@vue/test-utils'; diff --git a/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue index 6836f1f7..de231e1f 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue +++ b/src/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue @@ -14,8 +14,6 @@ import { containsLineItemWithPartType } from '@/helpers/service-package-helper.js'; -const store = useMainStore(); - export default { name: 'service-package-review', components: { @@ -100,8 +98,8 @@ export default { }, methods: { loadInitialData() { - const wipersPromise = store.getWipers(); - const rainDefensePromise = store.getRainDefense(); + const wipersPromise = useMainStore().getWipers(); + const rainDefensePromise = useMainStore().getRainDefense(); const promiseResultMap = [ { diff --git a/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js index fd4a3d64..981980d0 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js +++ b/src/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.spec.js @@ -1,5 +1,5 @@ // Components -import vehicleReview from '@/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue'; +import vehicleReview from '@/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue'; // Supporting Files import { shallowMount } from '@vue/test-utils'; From 73bf00cdd59c1053e2df9548f55934772745ab3e Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 19 Jan 2024 11:56:52 -0500 Subject: [PATCH 473/674] Fixing vehicle damage lines --- .../damage-review-content-generator.js | 71 ++++++++++++ .../damage-review/damage-review.vue | 109 +++--------------- .../tpa-submit/review-block/review-block.vue | 4 +- src/layouts/tpa-submit/tpa-submit.vue | 43 +++++-- src/store/index.js | 2 +- 5 files changed, 127 insertions(+), 102 deletions(-) create mode 100644 src/helpers/damage-review-content-generator.js diff --git a/src/helpers/damage-review-content-generator.js b/src/helpers/damage-review-content-generator.js new file mode 100644 index 00000000..a6d8f7b5 --- /dev/null +++ b/src/helpers/damage-review-content-generator.js @@ -0,0 +1,71 @@ +import damageLocationsSelected from '@/constants/damage-locations-selected.js'; + +function getLocationAnswer(damageLocation, locationAnswers) { + return locationAnswers?.find((answer) => answer.Name === damageLocation); +} + +function getGlassPieces(damageLocation, glassToReplace) { + return glassToReplace?.filter((item) => item.glassLocation === damageLocation); +} + +function getWindshieldCopy(answerContent, glassToReplace, isRepair) { + const windshieldPieces = getGlassPieces(damageLocationsSelected.WINDSHIELD, glassToReplace); + return isRepair || !!windshieldPieces?.length ? [answerContent?.Text] : []; +} + +function getRearCopy(answerContent, glassToReplace) { + const rearPieces = getGlassPieces(damageLocationsSelected.REAR, glassToReplace); + return rearPieces?.length ? [answerContent?.Text] : []; +} + +function generateBulletedListFromAnswers(answers) { + const items = answers.map((answer) => `
  • ${answer.Text}
  • `); + return `
      ${items.join('')}
    `; +} + +function getSideCopy(location, locationAnswers, damageAnswers, glassToReplace) { + const sideItems = getGlassPieces(location, glassToReplace); + const damageAnswersOnOrder = damageAnswers?.filter((answer) => + sideItems?.some((glassPiece) => answer.Name === glassPiece.glassName)); + + return sideItems?.length + ? [ + locationAnswers?.Text, + generateBulletedListFromAnswers(damageAnswersOnOrder) + ] + : []; +} + +function getDamageDisplayContent( + locationAnswers, + driverSideDamageAnswers, + passengerSideDamageAnswers, + glassToReplace, + isRepair +) { + return [ + ...getWindshieldCopy( + getLocationAnswer(damageLocationsSelected.WINDSHIELD, locationAnswers), + glassToReplace, + isRepair + ), + ...getSideCopy( + damageLocationsSelected.DRIVER, + getLocationAnswer(damageLocationsSelected.DRIVER, locationAnswers), + driverSideDamageAnswers, + glassToReplace + ), + ...getSideCopy( + damageLocationsSelected.PASSENGER, + getLocationAnswer(damageLocationsSelected.PASSENGER, locationAnswers), + passengerSideDamageAnswers, + glassToReplace + ), + ...getRearCopy( + getLocationAnswer(damageLocationsSelected.REAR, locationAnswers), + glassToReplace + ) + ]; +} + +export { getDamageDisplayContent, getLocationAnswer }; diff --git a/src/layouts/review-page/review-sections/damage-review/damage-review.vue b/src/layouts/review-page/review-sections/damage-review/damage-review.vue index 4e0b0878..a2e4a2a3 100644 --- a/src/layouts/review-page/review-sections/damage-review/damage-review.vue +++ b/src/layouts/review-page/review-sections/damage-review/damage-review.vue @@ -9,6 +9,8 @@ diff --git a/src/layouts/tpa-submit/review-block/review-block.vue b/src/layouts/tpa-submit/review-block/review-block.vue index 5d13e48f..4f5af710 100644 --- a/src/layouts/tpa-submit/review-block/review-block.vue +++ b/src/layouts/tpa-submit/review-block/review-block.vue @@ -21,8 +21,8 @@

    - {{ line }} + class="small review-block__body--line" + v-html="line">

    diff --git a/src/layouts/tpa-submit/tpa-submit.vue b/src/layouts/tpa-submit/tpa-submit.vue index 1ba7f98a..6a0afbbf 100644 --- a/src/layouts/tpa-submit/tpa-submit.vue +++ b/src/layouts/tpa-submit/tpa-submit.vue @@ -78,7 +78,9 @@ :customText="orderDetailsBody" :marginTopSizeOverride="4" class="mb-4 px-4 small text-color--darker-gray" /> - +
    this.navigate(scenario) }; }, forwardButtonAction() { this.navigate(this.navigationScenarios.CLICKED_FORWARD); }, - getNavigateByScenarioMethod(scenario) { - return () => this.navigate(scenario); - }, navigate(scenario) { this.$router.navigate(scenario, this.$route); }, @@ -255,12 +276,18 @@ export default { return null; } }, + getAnswersNullSafe(widgetName) { + const rawAnswers = this.getCmsContent(widgetName, 'Answers'); + return rawAnswers || []; + }, processIfStatements, getStringWithCustomValues, toDisplayPhoneNumber, toTitleCase, formatAddress, - formatAmountInDollars + formatAmountInDollars, + getDamageDisplayContent, + getLocationAnswer } }; diff --git a/src/store/index.js b/src/store/index.js index 0249b80c..facfa026 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -13,7 +13,6 @@ 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 endorsementOptions from '@/constants/endorsement-options'; const storeId = 'main'; @@ -220,6 +219,7 @@ export const useMainStore = defineStore({ lineItems: (state) => state.order.lineItems, payment: (state) => state.order.payment, policy: (state) => state.order.policy, + hasExactlyOneChip: () => state.order.damage.numberOfChips === 1, 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, From 0fdc6c54e7548103273d8a9675069e72491db938 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Fri, 19 Jan 2024 17:10:55 -0500 Subject: [PATCH 474/674] tpa-conf WIP --- .../tpa-confirmation/tpa-confirmation.vue | 68 ++++++++++++++++--- .../router-constants/navigation-scenarios.js | 3 + src/router/router-constants/routing-table.js | 4 ++ 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/layouts/tpa-confirmation/tpa-confirmation.vue b/src/layouts/tpa-confirmation/tpa-confirmation.vue index 23817e5b..9eabddb5 100644 --- a/src/layouts/tpa-confirmation/tpa-confirmation.vue +++ b/src/layouts/tpa-confirmation/tpa-confirmation.vue @@ -7,14 +7,25 @@
    -
    +
    +
    + + +
    diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 0d4376aa..142aa087 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -74,6 +74,9 @@ const navigationScenarios = Object.freeze({ EDIT_PREFERRED_SHOP: 'EDIT_PREFERRED_SHOP', EDIT_CONTACT_DETAILS: 'EDIT_CONTACT_DETAILS', + // TPA Confirmation + REQUEST_CALLBACK: 'REQUEST_CALLBACK', + // Provider Preference CLICKED_FORWARD_WITH_SAFELITE: 'CLICKED_FORWARD_WITH_SAFELITE', CLICKED_FORWARD_WITH_TPA_ENABLED: 'CLICKED_FORWARD_WITH_TPA_ENABLED', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 2cded6f6..365a6dd0 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -659,6 +659,10 @@ const routingTable = () => [ { scenario: navigationScenarios.CLICKED_FORWARD, destinationIssPageValue: issPageValues.WELCOME_PAGE + }, + { + scenario: navigationScenarios.REQUEST_CALLBACK, + destinationIssPageValue: issPageValues.BAILOUT_PAGE } ] }, From 002ef3726d29c9c4d761d35e16593b4e520b51eb Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 22 Jan 2024 10:45:08 -0500 Subject: [PATCH 475/674] Removing unnecessary methods --- .../__snapshots__/tpa-submit.spec.js.snap | 1 + src/layouts/tpa-submit/tpa-submit.spec.js | 42 ++++++++++--------- src/layouts/tpa-submit/tpa-submit.vue | 31 +++++--------- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/layouts/tpa-submit/__snapshots__/tpa-submit.spec.js.snap b/src/layouts/tpa-submit/__snapshots__/tpa-submit.spec.js.snap index 10ea690d..48eedef7 100644 --- a/src/layouts/tpa-submit/__snapshots__/tpa-submit.spec.js.snap +++ b/src/layouts/tpa-submit/__snapshots__/tpa-submit.spec.js.snap @@ -8,6 +8,7 @@ Object { }, "sections": Array [], "widget": Object { + "damageLocations": "DamageLocationsWidget", "footer": "SiteFooterWidget", "orderDetails": "OrderDetailsContent", "serviceSummary": "ServiceSummaryContent", diff --git a/src/layouts/tpa-submit/tpa-submit.spec.js b/src/layouts/tpa-submit/tpa-submit.spec.js index 7b326679..76edc8c8 100644 --- a/src/layouts/tpa-submit/tpa-submit.spec.js +++ b/src/layouts/tpa-submit/tpa-submit.spec.js @@ -9,6 +9,7 @@ import { useMainStore } from '@/store'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import settleAllPromises from '@/helpers/layout-helper.js'; import widgetFields from '@/constants/cms-widget-fields.js'; +import { toTitleCase, formatAddress, toDisplayPhoneNumber } from '@/helpers/text-helper.js'; // Mock fetchCmsContentForPage jest.mock('@/helpers/cms-content-helper', () => ({ @@ -57,6 +58,11 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu return { wrapper }; } +beforeEach(() => { + formatAddress.mockClear(); + toDisplayPhoneNumber.mockClear(); +}); + describe('tpa-submit', () => { test('returns the initial data', () => { // Arrange @@ -337,11 +343,12 @@ describe('tpa-submit', () => { expect(vehicleSection.lines).toStrictEqual(expectedLines); } ); + // TODO update because this case is now much more complicated test.each([ - ['Apple sauce', 'Apple sauce'], - ['', ''], - ['', undefined], - ['', null] + ['Apple sauce', 'Apple sauce']// , + // ['', ''], + // ['', undefined], + // ['', null] ])( 'damage line is %p when store damage is %p', async (damageLine, storeDamage) => { @@ -386,15 +393,12 @@ describe('tpa-submit', () => { const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex]; expect(preferredShopSection.lines.length).toBe(3); }); - test.each([ - ['some value', 'some value'], - ['', ''], - ['', null], - ['', undefined] - ])('first line is %p when company name is %p', async (line, companyName) => { + test('first line is value returned from toTitleCase method', async () => { // Arrange - const initialData = { companyName }; + const initialData = { companyName: 'some value' }; const { wrapper } = getMountedComponent({}, initialData); + const expectedName = 'some expected name'; + toTitleCase.mockImplementationOnce(() => expectedName); const preferredShopSectionIndex = 2; // Act @@ -407,7 +411,7 @@ describe('tpa-submit', () => { // Assert const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex]; - expect(preferredShopSection.lines[0]).toBe(line); + expect(preferredShopSection.lines[0]).toBe(expectedName); }); test('second line is expected and formatAddress called', async () => { // Arrange @@ -426,7 +430,7 @@ describe('tpa-submit', () => { }; const { wrapper } = getMountedComponent(initialStore); const line = 'some returned line'; - wrapper.vm.formatAddress = jest.fn().mockImplementationOnce(() => line); + formatAddress.mockImplementationOnce(() => line); const preferredShopSectionIndex = 2; // Act @@ -440,8 +444,8 @@ describe('tpa-submit', () => { // Assert const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex]; expect(preferredShopSection.lines[1]).toBe(line); - expect(wrapper.vm.formatAddress).toHaveBeenCalledTimes(1); - expect(wrapper.vm.formatAddress).toHaveBeenCalledWith( + expect(formatAddress).toHaveBeenCalledTimes(1); + expect(formatAddress).toHaveBeenCalledWith( address.streetAddress, null, address.city, @@ -461,7 +465,7 @@ describe('tpa-submit', () => { }; const { wrapper } = getMountedComponent(initialStore); const expectedLine = 'returned from to display phone num'; - wrapper.vm.toDisplayPhoneNumber = jest.fn().mockImplementationOnce(() => expectedLine); + toDisplayPhoneNumber.mockImplementationOnce(() => expectedLine); const preferredShopSectionIndex = 2; // Act @@ -475,7 +479,7 @@ describe('tpa-submit', () => { // Assert const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex]; expect(preferredShopSection.lines[2]).toBe(expectedLine); - expect(wrapper.vm.toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber); + expect(toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber); }); }); test('contact info section has expected content', async () => { @@ -498,7 +502,7 @@ describe('tpa-submit', () => { const expectedLine1 = 'Jones Eddison'; const expectedLine2 = emailAddress; const expectedLine3 = 'some value returned'; - wrapper.vm.toDisplayPhoneNumber = jest.fn().mockImplementation((number) => (number === phoneNumber ? expectedLine3 : '')); + toDisplayPhoneNumber.mockImplementation((number) => (number === phoneNumber ? expectedLine3 : '')); const contactInfoSectionIndex = 3; // Act @@ -514,7 +518,7 @@ describe('tpa-submit', () => { expect(contactInfoSection.lines[0]).toBe(expectedLine1); expect(contactInfoSection.lines[1]).toBe(expectedLine2); expect(contactInfoSection.lines[2]).toBe(expectedLine3); - expect(wrapper.vm.toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber); + expect(toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber); }); }); describe('computed', () => { diff --git a/src/layouts/tpa-submit/tpa-submit.vue b/src/layouts/tpa-submit/tpa-submit.vue index 6a0afbbf..8a241e05 100644 --- a/src/layouts/tpa-submit/tpa-submit.vue +++ b/src/layouts/tpa-submit/tpa-submit.vue @@ -171,7 +171,7 @@ export default { }, subHeaderBodyTwo() { const cmsContent = this.getCmsContent(this.widget.siteSubHeader, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2); - return this.getStringWithCustomValues(cmsContent, this.customValueMap); + return getStringWithCustomValues(cmsContent, this.customValueMap); }, serviceSummaryText() { return this.getCmsContent(this.widget.serviceSummary, widgetFields.TEXT_BLOCK_WIDGET.TEXT); @@ -181,7 +181,7 @@ export default { }, orderDetailsBody() { const orderDetailsBodyText = this.getCmsContent(this.widget.orderDetails, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT); - return this.processIfStatements(orderDetailsBodyText, 'custom', this.getCustomValueFromString); + return processIfStatements(orderDetailsBodyText, 'custom', this.getCustomValueFromString); }, forwardButtonText() { return this.getCmsContent(this.widget.footer, widgetFields.FOOTER_WIDGET.FORWARD_BUTTON_TEXT); @@ -193,7 +193,7 @@ export default { return useMainStore().order.currentDeductible; }, deductibleBoxValue() { - return this.isVerified ? this.formatAmountInDollars(this.currentDeductible) : VERIFYING_COVERAGE; + return this.isVerified ? formatAmountInDollars(this.currentDeductible) : VERIFYING_COVERAGE; }, getVehicleLines() { const { year, make, model } = useMainStore().order.vehicle; @@ -206,17 +206,16 @@ export default { return this.getAnswersNullSafe(this.widget.damageLocations); }, driverSideDamageAnswers() { - const answerContent = this.getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers); + const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers); return this.getAnswersNullSafe(answerContent?.SubWidgetName); }, passengerSideDamageAnswers() { - const answerContent = this.getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers); + const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers); return this.getAnswersNullSafe(answerContent?.SubWidgetName); }, - // TODO finish getDamageLines() { const { glassToReplace, isRepair } = useMainStore().order.damage; - return this.getDamageDisplayContent( + return getDamageDisplayContent( this.locationAnswers, this.driverSideDamageAnswers, this.passengerSideDamageAnswers, @@ -227,16 +226,16 @@ export default { getPreferredShopLines() { const { phoneNumber, address } = useMainStore().order.serviceLocation.provider; const { streetAddress, city, state, zipCode } = address; - const displayAddress = this.formatAddress(streetAddress, null, city, state, zipCode); - const displayPhoneNumber = this.toDisplayPhoneNumber(phoneNumber); - return [this.toTitleCase(this.companyName ?? ''), displayAddress, displayPhoneNumber]; + const displayAddress = formatAddress(streetAddress, null, city, state, zipCode); + const displayPhoneNumber = toDisplayPhoneNumber(phoneNumber); + return [toTitleCase(this.companyName ?? ''), displayAddress, displayPhoneNumber]; }, getContactInfoLines() { const { firstName, lastName, emailAddress, phoneNumber } = useMainStore().contactInfo; return [ `${firstName} ${lastName}`, emailAddress ?? '', - this.toDisplayPhoneNumber(phoneNumber) + toDisplayPhoneNumber(phoneNumber) ]; } }, @@ -279,15 +278,7 @@ export default { getAnswersNullSafe(widgetName) { const rawAnswers = this.getCmsContent(widgetName, 'Answers'); return rawAnswers || []; - }, - processIfStatements, - getStringWithCustomValues, - toDisplayPhoneNumber, - toTitleCase, - formatAddress, - formatAmountInDollars, - getDamageDisplayContent, - getLocationAnswer + } } }; From 5121c70bcca9efc2cac5e8519ba21697e5129e18 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 22 Jan 2024 11:12:00 -0500 Subject: [PATCH 476/674] Updating tpa-submit tests --- src/layouts/tpa-submit/tpa-submit.spec.js | 71 +++++++++++++---------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/src/layouts/tpa-submit/tpa-submit.spec.js b/src/layouts/tpa-submit/tpa-submit.spec.js index 76edc8c8..50b01bc9 100644 --- a/src/layouts/tpa-submit/tpa-submit.spec.js +++ b/src/layouts/tpa-submit/tpa-submit.spec.js @@ -10,6 +10,7 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import settleAllPromises from '@/helpers/layout-helper.js'; import widgetFields from '@/constants/cms-widget-fields.js'; import { toTitleCase, formatAddress, toDisplayPhoneNumber } from '@/helpers/text-helper.js'; +import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js'; // Mock fetchCmsContentForPage jest.mock('@/helpers/cms-content-helper', () => ({ @@ -26,6 +27,11 @@ jest.mock('@/helpers/text-helper.js', () => ({ toTitleCase: jest.fn() })); +jest.mock('@/helpers/damage-review-content-generator.js', () => ({ + getDamageDisplayContent: jest.fn(), + getLocationAnswer: jest.fn() +})); + // Mock our module for promises. jest.mock('@/helpers/layout-helper.js', () => jest.fn()); @@ -61,6 +67,7 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu beforeEach(() => { formatAddress.mockClear(); toDisplayPhoneNumber.mockClear(); + getDamageDisplayContent.mockClear(); }); describe('tpa-submit', () => { @@ -343,38 +350,25 @@ describe('tpa-submit', () => { expect(vehicleSection.lines).toStrictEqual(expectedLines); } ); - // TODO update because this case is now much more complicated - test.each([ - ['Apple sauce', 'Apple sauce']// , - // ['', ''], - // ['', undefined], - // ['', null] - ])( - 'damage line is %p when store damage is %p', - async (damageLine, storeDamage) => { - // Arrange - const initialStore = { - order: { - policy: { damageCause: storeDamage } - } - }; - const { wrapper } = getMountedComponent(initialStore); - const damageSectionIndex = 1; - const expectedLines = [damageLine]; + test('damage section lines equal result from getDamageDisplayContent', async () => { + // Arrange + const { wrapper } = getMountedComponent(); + const damageSectionIndex = 1; + const expectedLines = ['hi', 'potato', 'vehicle 3']; + getDamageDisplayContent.mockImplementationOnce(() => expectedLines); - // Act - await tpaSubmit.beforeRouteEnter.call( - wrapper.vm, - { query: { issPage: 'tpa-submit' } }, - undefined, - (c) => c(wrapper.vm) - ); + // Act + await tpaSubmit.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: 'tpa-submit' } }, + undefined, + (c) => c(wrapper.vm) + ); - // Assert - const damageSection = wrapper.vm.sections[damageSectionIndex]; - expect(damageSection.lines).toStrictEqual(expectedLines); - } - ); + // Assert + const damageSection = wrapper.vm.sections[damageSectionIndex]; + expect(damageSection.lines).toEqual(expectedLines); + }); describe('preferred shop section', () => { test('has three lines', async () => { // Arrange @@ -766,5 +760,22 @@ describe('tpa-submit', () => { expect(result).toBe(null); }); }); + test.each([ + [[1, 5, 6], [1, 5, 6]], + [[], []], + [undefined, []], + [null, []] + ])('getAnswersNullSafe', (rawAnswers, expected) => { + // Arrange + const widgetName = 'WidgetName'; + const { wrapper } = getMountedComponent(); + wrapper.vm.getCmsContent = jest.fn().mockImplementationOnce(() => rawAnswers); + + // Act + const result = wrapper.vm.getAnswersNullSafe(widgetName); + + // Assert + expect(result).toEqual(expected); + }); }); }); From a84c0081c85f874b832bde12784e7690690b6f99 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 22 Jan 2024 16:14:49 -0500 Subject: [PATCH 477/674] Updating damage review tests --- .../damage-review-content-generator.spec.js | 411 +++++++++++++++++ .../damage-review/damage-review.spec.js | 428 ++---------------- 2 files changed, 446 insertions(+), 393 deletions(-) create mode 100644 src/helpers/damage-review-content-generator.spec.js diff --git a/src/helpers/damage-review-content-generator.spec.js b/src/helpers/damage-review-content-generator.spec.js new file mode 100644 index 00000000..8a20d7d7 --- /dev/null +++ b/src/helpers/damage-review-content-generator.spec.js @@ -0,0 +1,411 @@ +import { getDamageDisplayContent, getLocationAnswer } from '@/helpers/damage-review-content-generator.js'; +import damageLocationsSelected from '@/constants/damage-locations-selected'; + +const testConstants = { + cmsConstants: { + widgetNames: { + locations: 'DamageLocationsWidget', + driverDamages: 'DriverDamagesWidget', + passengerDamages: 'PassengerDamagesWidget' + }, + damageLocations: { + windshield: damageLocationsSelected.WINDSHIELD, + driver: damageLocationsSelected.DRIVER, + passenger: damageLocationsSelected.PASSENGER, + rear: damageLocationsSelected.REAR + }, + damageNames: { + vent: damageLocationsSelected.VENT, + front: damageLocationsSelected.FRONT, + back: damageLocationsSelected.BACK, + quarter: damageLocationsSelected.QUARTER, + side: damageLocationsSelected.SIDEDOOR + }, + locationCopy: { + windshield: 'Windshield copy', + driver: 'Driver copy', + passenger: 'Passenger copy', + rear: 'Rear copy' + }, + damageCopy: { + vent: 'Vent copy', + front: 'Front copy', + back: 'Back copy', + quarter: 'Quarter copy', + side: 'Side copy' + }, + imageId: '00000000-0000-0000-0000-000000000000' + }, + glassItems: { + windshield: { + glassLocation: damageLocationsSelected.WINDSHIELD, + glassName: damageLocationsSelected.SINGLE + }, + rear: { + glassLocation: damageLocationsSelected.REAR, + glassName: damageLocationsSelected.STATIONARY + }, + passengerItems: { + vent: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.VENT + }, + front: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.FRONT + }, + back: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.BACK + }, + quarter: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.QUARTER + }, + side: { + glassLocation: damageLocationsSelected.PASSENGER, + glassName: damageLocationsSelected.SIDEDOOR + } + }, + driverItems: { + vent: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.VENT + }, + front: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.FRONT + }, + back: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.BACK + }, + quarter: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.QUARTER + }, + side: { + glassLocation: damageLocationsSelected.DRIVER, + glassName: damageLocationsSelected.SIDEDOOR + } + } + } +}; +const cmsContent = { + DamageLocationsWidget: { + Answers: [ + { + Name: testConstants.cmsConstants.damageLocations.windshield, + Text: testConstants.cmsConstants.locationCopy.windshield, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageLocations.driver, + Text: testConstants.cmsConstants.locationCopy.driver, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: testConstants.cmsConstants.widgetNames.driverDamages + }, + { + Name: testConstants.cmsConstants.damageLocations.passenger, + Text: testConstants.cmsConstants.locationCopy.passenger, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: testConstants.cmsConstants.widgetNames.passengerDamages + }, + { + Name: testConstants.cmsConstants.damageLocations.rear, + Text: testConstants.cmsConstants.locationCopy.rear, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + } + ] + }, + DriverDamagesWidget: { + Answers: [ + { + Name: testConstants.cmsConstants.damageNames.vent, + Text: testConstants.cmsConstants.damageCopy.vent, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.front, + Text: testConstants.cmsConstants.damageCopy.front, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.back, + Text: testConstants.cmsConstants.damageCopy.back, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.quarter, + Text: testConstants.cmsConstants.damageCopy.quarter, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.side, + Text: testConstants.cmsConstants.damageCopy.side, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + } + ] + }, + PassengerDamagesWidget: { + Answers: [ + { + Name: testConstants.cmsConstants.damageNames.vent, + Text: testConstants.cmsConstants.damageCopy.vent, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.front, + Text: testConstants.cmsConstants.damageCopy.front, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.back, + Text: testConstants.cmsConstants.damageCopy.back, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.quarter, + Text: testConstants.cmsConstants.damageCopy.quarter, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + }, + { + Name: testConstants.cmsConstants.damageNames.side, + Text: testConstants.cmsConstants.damageCopy.side, + SubText: '', + ImageId: testConstants.cmsConstants.imageId, + Image: '', + SubWidgetName: '' + } + ] + } +}; + +describe('damage-review-content-generator', () => { + describe('getLocationAnswer', () => { + test('answer with damage location name match', () => { + // Arrange + const damageLocation = 'matching name'; + const expected = { Name: damageLocation }; + const locationAnswers = [{ Name: 'non matching name' }, expected]; + + // Act + const result = getLocationAnswer(damageLocation, locationAnswers); + + // Assert + expect(result).toEqual(expected); + }); + test('no damage location name match', () => { + // Arrange + const damageLocation = 'random string'; + const locationAnswers = [{ Name: 'non matching name' }]; + + // Act + const result = getLocationAnswer(damageLocation, locationAnswers); + + // Assert + expect(result).toBe(undefined); + }); + test.each([ + [[]], + [null], + [undefined] + ])('location answers %p', (locationAnswers) => { + // Arrange + const damageLocation = 'some string'; + + // Act + const result = getLocationAnswer(damageLocation, locationAnswers); + + // Assert + expect(result).toBe(undefined); + }); + }); + describe('Correctly assembles damage info into a display string', () => { + const locationAnswers = cmsContent.DamageLocationsWidget.Answers; + test('Shows windshield copy when windshield damage is included', async () => { + // Arrange + const glassToReplace = [testConstants.glassItems.windshield]; + const isRepair = false; + + // Act + const result = getDamageDisplayContent(locationAnswers, null, null, glassToReplace, isRepair); + + // Assert + expect(result).toStrictEqual([ + testConstants.cmsConstants.locationCopy.windshield + ]); + }); + + test('Windshield copy is shown when order is a repair', async () => { + // Arrange + const glassToReplace = []; + const isRepair = true; + + // Act + const result = getDamageDisplayContent(locationAnswers, null, null, glassToReplace, isRepair); + + // Assert + expect(result).toStrictEqual([ + testConstants.cmsConstants.locationCopy.windshield + ]); + }); + + test('Rear windshield copy shows when rear damage is present', async () => { + // Arrange + const glassToReplace = [testConstants.glassItems.rear]; + const isRepair = false; + + // Act + const result = getDamageDisplayContent(locationAnswers, null, null, glassToReplace, isRepair); + + // Assert + expect(result).toStrictEqual([ + testConstants.cmsConstants.locationCopy.rear + ]); + }); + + test('Driver side copy and items are shown when driver side damage is present', async () => { + // Arrange + const driverSideDamageAnswers = cmsContent.DriverDamagesWidget.Answers; + const glassToReplace = [ + testConstants.glassItems.driverItems.back, + testConstants.glassItems.driverItems.front + ]; + const isRepair = false; + const expectedList = '
      ' + + `
    • ${testConstants.cmsConstants.damageCopy.front}
    • ` + + `
    • ${testConstants.cmsConstants.damageCopy.back}
    • ` + + '
    '; + + // Act + const result = getDamageDisplayContent( + locationAnswers, + driverSideDamageAnswers, + null, + glassToReplace, + isRepair + ); + + // Assert + expect(result).toStrictEqual([ + testConstants.cmsConstants.locationCopy.driver, + expectedList + ]); + }); + + test('Passenger side copy and items are shown when passenger side damage is present', async () => { + // Arrange + const passengerSideDamageAnswers = cmsContent.PassengerDamagesWidget.Answers; + const glassToReplace = [ + testConstants.glassItems.passengerItems.quarter, + testConstants.glassItems.passengerItems.vent, + testConstants.glassItems.passengerItems.side + ]; + const isRepair = false; + const expectedList = '
      ' + + `
    • ${testConstants.cmsConstants.damageCopy.vent}
    • ` + + `
    • ${testConstants.cmsConstants.damageCopy.quarter}
    • ` + + `
    • ${testConstants.cmsConstants.damageCopy.side}
    • ` + + '
    '; + + // Act + const result = getDamageDisplayContent( + locationAnswers, + null, + passengerSideDamageAnswers, + glassToReplace, + isRepair + ); + + // Assert + expect(result).toStrictEqual([ + testConstants.cmsConstants.locationCopy.passenger, + expectedList + ]); + }); + + test('All relevant sections are shown in order in multiglass scenario', async () => { + // Arrange + const driverSideDamageAnswers = cmsContent.DriverDamagesWidget.Answers; + const passengerSideDamageAnswers = cmsContent.PassengerDamagesWidget.Answers; + const glassToReplace = [ + testConstants.glassItems.windshield, + testConstants.glassItems.rear, + testConstants.glassItems.driverItems.vent, + testConstants.glassItems.driverItems.front, + testConstants.glassItems.driverItems.back, + testConstants.glassItems.passengerItems.quarter, + testConstants.glassItems.passengerItems.back, + testConstants.glassItems.passengerItems.side + ]; + const isRepair = false; + const expectedDriverDamageList = '
      ' + + `
    • ${testConstants.cmsConstants.damageCopy.vent}
    • ` + + `
    • ${testConstants.cmsConstants.damageCopy.front}
    • ` + + `
    • ${testConstants.cmsConstants.damageCopy.back}
    • ` + + '
    '; + const expectedPassengerDamageList = '
      ' + + `
    • ${testConstants.cmsConstants.damageCopy.back}
    • ` + + `
    • ${testConstants.cmsConstants.damageCopy.quarter}
    • ` + + `
    • ${testConstants.cmsConstants.damageCopy.side}
    • ` + + '
    '; + + // Act + const result = getDamageDisplayContent( + locationAnswers, + driverSideDamageAnswers, + passengerSideDamageAnswers, + glassToReplace, + isRepair + ); + + // Assert + expect(result).toStrictEqual([ + testConstants.cmsConstants.locationCopy.windshield, + testConstants.cmsConstants.locationCopy.driver, + expectedDriverDamageList, + testConstants.cmsConstants.locationCopy.passenger, + expectedPassengerDamageList, + testConstants.cmsConstants.locationCopy.rear + ]); + }); + }); +}); diff --git a/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js index 4a0a2fa7..5e369a72 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js +++ b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.spec.js @@ -2,113 +2,16 @@ import damageReview from '@/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue'; // Supporting Files +import { createTestingPinia } from '@pinia/testing'; +import { useMainStore } from '@/store'; import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; -import damageLocationsSelected from '@/constants/damage-locations-selected'; +import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js'; -const testConstants = { - cmsConstants: { - widgetNames: { - header: 'DamageReviewWidget', - locations: 'DamageLocationsWidget', - driverDamages: 'DriverDamagesWidget', - passengerDamages: 'PassengerDamagesWidget' - }, - header: { - text: 'Damage' - }, - damageLocations: { - windshield: damageLocationsSelected.WINDSHIELD, - driver: damageLocationsSelected.DRIVER, - passenger: damageLocationsSelected.PASSENGER, - rear: damageLocationsSelected.REAR - }, - damageNames: { - vent: damageLocationsSelected.VENT, - front: damageLocationsSelected.FRONT, - back: damageLocationsSelected.BACK, - quarter: damageLocationsSelected.QUARTER, - side: damageLocationsSelected.SIDEDOOR - }, - locationCopy: { - windshield: 'Windshield copy', - driver: 'Driver copy', - passenger: 'Passenger copy', - rear: 'Rear copy' - }, - damageCopy: { - vent: 'Vent copy', - front: 'Front copy', - back: 'Back copy', - quarter: 'Quarter copy', - side: 'Side copy' - }, - imageId: '00000000-0000-0000-0000-000000000000' - }, - makeBulletedList: (items) => { - let list = '
      '; - items.forEach((item) => { - list += `
    • ${item}
    • `; - }); - list += '
    '; - - return list; - }, - glassItems: { - windshield: { - glassLocation: damageLocationsSelected.WINDSHIELD, - glassName: damageLocationsSelected.SINGLE - }, - rear: { - glassLocation: damageLocationsSelected.REAR, - glassName: damageLocationsSelected.STATIONARY - }, - passengerItems: { - vent: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.VENT - }, - front: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.FRONT - }, - back: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.BACK - }, - quarter: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.QUARTER - }, - side: { - glassLocation: damageLocationsSelected.PASSENGER, - glassName: damageLocationsSelected.SIDEDOOR - } - }, - driverItems: { - vent: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.VENT - }, - front: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.FRONT - }, - back: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.BACK - }, - quarter: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.QUARTER - }, - side: { - glassLocation: damageLocationsSelected.DRIVER, - glassName: damageLocationsSelected.SIDEDOOR - } - } - } -}; +jest.mock('@/helpers/damage-review-content-generator.js', () => ({ + getDamageDisplayContent: jest.fn(), + getLocationAnswer: jest.fn() +})); let cmsContent; const mockMixin = { @@ -117,15 +20,22 @@ const mockMixin = { } }; -function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { +function getShallowMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) { const mountOptions = getMountOptions({ router: { navigate: jest.fn() } }); + const testingPinia = createTestingPinia({ + initialState: { + main: mainInitialState + } + }); + useMainStore(testingPinia); methodToRun(); + mountOptions.global.plugins = [testingPinia]; mountOptions.data = () => ( initialData ); @@ -137,300 +47,32 @@ function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { } beforeEach(() => { - cmsContent = { - DamageReviewWidget: { - Text: testConstants.cmsConstants.header.text - }, - DamageLocationsWidget: { - Answers: [ - { - Name: testConstants.cmsConstants.damageLocations.windshield, - Text: testConstants.cmsConstants.locationCopy.windshield, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageLocations.driver, - Text: testConstants.cmsConstants.locationCopy.driver, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: testConstants.cmsConstants.widgetNames.driverDamages - }, - { - Name: testConstants.cmsConstants.damageLocations.passenger, - Text: testConstants.cmsConstants.locationCopy.passenger, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: testConstants.cmsConstants.widgetNames.passengerDamages - }, - { - Name: testConstants.cmsConstants.damageLocations.rear, - Text: testConstants.cmsConstants.locationCopy.rear, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - } - ] - }, - DriverDamagesWidget: { - Answers: [ - { - Name: testConstants.cmsConstants.damageNames.vent, - Text: testConstants.cmsConstants.damageCopy.vent, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.front, - Text: testConstants.cmsConstants.damageCopy.front, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.back, - Text: testConstants.cmsConstants.damageCopy.back, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.quarter, - Text: testConstants.cmsConstants.damageCopy.quarter, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.side, - Text: testConstants.cmsConstants.damageCopy.side, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - } - ] - }, - PassengerDamagesWidget: { - Answers: [ - { - Name: testConstants.cmsConstants.damageNames.vent, - Text: testConstants.cmsConstants.damageCopy.vent, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.front, - Text: testConstants.cmsConstants.damageCopy.front, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.back, - Text: testConstants.cmsConstants.damageCopy.back, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.quarter, - Text: testConstants.cmsConstants.damageCopy.quarter, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - }, - { - Name: testConstants.cmsConstants.damageNames.side, - Text: testConstants.cmsConstants.damageCopy.side, - SubText: '', - ImageId: testConstants.cmsConstants.imageId, - Image: '', - SubWidgetName: '' - } - ] - } - }; + getDamageDisplayContent.mockClear(); }); describe('Damage Review Block', () => { - describe('Correctly assembles damage info into a display string', () => { - test('Shows windshield copy when windshield damage is included', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, + test('computed displayContent calls getDamageDisplayContent with expected', () => { + // Arrange + const glassToReplace = ['front-window', 'side-window']; + const isRepair = false; + const initialStore = { + order: { damage: { - isRepair: false, - glassToReplace: [testConstants.glassItems.windshield] + glassToReplace, + isRepair } - }); + } + }; + const expected = ['a', 'v', 'n']; + getDamageDisplayContent.mockImplementationOnce(() => expected); + const { wrapper } = getShallowMountedComponent(initialStore, {}); - // Act - await wrapper.vm.$nextTick(); + // Act + const result = wrapper.vm.displayContent; - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.windshield - ]); - }); - - test('Windshield copy is shown when order is a repair', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: true, - numberOfChips: 2, - glassToReplace: [] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.windshield - ]); - }); - - test('Rear windshield copy shows when rear damage is present', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - numberOfChips: null, - glassToReplace: [testConstants.glassItems.rear] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.rear - ]); - }); - - test('Driver side copy and items are shown when driver side damage is present', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - numberOfChips: null, - glassToReplace: [ - testConstants.glassItems.driverItems.back, - testConstants.glassItems.driverItems.front - ] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.driver, - testConstants.makeBulletedList([ - testConstants.cmsConstants.damageCopy.front, - testConstants.cmsConstants.damageCopy.back - ]) - ]); - }); - - test('Passenger side copy and items are shown when passenger side damage is present', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - numberOfChips: null, - glassToReplace: [ - testConstants.glassItems.passengerItems.quarter, - testConstants.glassItems.passengerItems.vent, - testConstants.glassItems.passengerItems.side - ] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.passenger, - testConstants.makeBulletedList([ - testConstants.cmsConstants.damageCopy.vent, - testConstants.cmsConstants.damageCopy.quarter, - testConstants.cmsConstants.damageCopy.side - ]) - ]); - }); - - test('All relevant sections are shown in order in multiglass scenario', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent({ - cmsWidgetName: testConstants.cmsConstants.widgetNames.header, - damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations, - damage: { - isRepair: false, - numberOfChips: null, - glassToReplace: [ - testConstants.glassItems.windshield, - testConstants.glassItems.rear, - testConstants.glassItems.driverItems.vent, - testConstants.glassItems.driverItems.front, - testConstants.glassItems.driverItems.back, - testConstants.glassItems.passengerItems.quarter, - testConstants.glassItems.passengerItems.back, - testConstants.glassItems.passengerItems.side - ] - } - }); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.displayContent).toStrictEqual([ - testConstants.cmsConstants.locationCopy.windshield, - testConstants.cmsConstants.locationCopy.driver, - testConstants.makeBulletedList([ - testConstants.cmsConstants.damageCopy.vent, - testConstants.cmsConstants.damageCopy.front, - testConstants.cmsConstants.damageCopy.back - ]), - testConstants.cmsConstants.locationCopy.passenger, - testConstants.makeBulletedList([ - testConstants.cmsConstants.damageCopy.back, - testConstants.cmsConstants.damageCopy.quarter, - testConstants.cmsConstants.damageCopy.side - ]), - testConstants.cmsConstants.locationCopy.rear - ]); - }); + // Assert + expect(result).toStrictEqual(expected); + expect(getDamageDisplayContent).toBeCalledTimes(1); + expect(getDamageDisplayContent).toBeCalledWith([], [], [], glassToReplace, isRepair); }); }); From 503ac4e1c6b9a9ae1b357ad334bc44e208a36b95 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 22 Jan 2024 16:18:44 -0500 Subject: [PATCH 478/674] Simplifying --- .../review-sections/damage-review/damage-review.vue | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue index 66089506..ac93b4bf 100644 --- a/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue +++ b/src/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue @@ -23,7 +23,7 @@ export default { computed: { displayContent() { const { glassToReplace, isRepair } = useMainStore().order.damage; - return this.getDamageDisplayContent( + return getDamageDisplayContent( this.locationAnswers, this.driverSideDamageAnswers, this.passengerSideDamageAnswers, @@ -32,11 +32,11 @@ export default { ); }, driverSideDamageAnswers() { - const answerContent = this.getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers); + const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers); return this.getAnswersNullSafe(answerContent?.SubWidgetName); }, passengerSideDamageAnswers() { - const answerContent = this.getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers); + const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers); return this.getAnswersNullSafe(answerContent?.SubWidgetName); }, locationAnswers() { @@ -47,9 +47,7 @@ export default { getAnswersNullSafe(widgetName) { const rawAnswers = this.getCmsContent(widgetName, 'Answers'); return rawAnswers || []; - }, - getDamageDisplayContent, - getLocationAnswer + } } }; From 0293b27ced33f142223db8276e3f182b4752b9ef Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 22 Jan 2024 16:52:03 -0500 Subject: [PATCH 479/674] Fixing routing --- src/layouts/tpa-submit/tpa-submit.vue | 5 ++++- src/router/router-constants/navigation-scenarios.js | 1 + src/router/router-constants/routing-table.js | 6 +++++- src/store/index.js | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/layouts/tpa-submit/tpa-submit.vue b/src/layouts/tpa-submit/tpa-submit.vue index 8a241e05..9886298f 100644 --- a/src/layouts/tpa-submit/tpa-submit.vue +++ b/src/layouts/tpa-submit/tpa-submit.vue @@ -242,8 +242,11 @@ export default { methods: { setSections() { + const vehicleScenario = useMainStore().isPolicyVehicle + ? this.navigationScenarios.EDIT_POLICY_VEHICLE + : this.navigationScenarios.EDIT_VEHICLE; this.sections = [ - this.getSection(this.widget.subheader.vehicle, this.getVehicleLines, this.navigationScenarios.EDIT_VEHICLE), + this.getSection(this.widget.subheader.vehicle, this.getVehicleLines, vehicleScenario), this.getSection(this.widget.subheader.damage, this.getDamageLines, this.navigationScenarios.EDIT_DAMAGE), this.getSection(this.widget.subheader.shop, this.getPreferredShopLines, this.navigationScenarios.EDIT_PREFERRED_SHOP), // eslint-disable-next-line max-len diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 0d4376aa..f71a452a 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -69,6 +69,7 @@ const navigationScenarios = Object.freeze({ CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP: 'CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP', // TPA Submit + EDIT_POLICY_VEHICLE: 'EDIT_POLICY_VEHICLE', EDIT_VEHICLE: 'EDIT_VEHICLE', EDIT_DAMAGE: 'EDIT_DAMAGE', EDIT_PREFERRED_SHOP: 'EDIT_PREFERRED_SHOP', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 43371dbe..22488935 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -641,6 +641,10 @@ const routingTable = () => [ { issPageValue: issPageValues.TPA_SUBMIT, maps: [ + { + scenario: navigationScenarios.EDIT_POLICY_VEHICLE, + destinationIssPageValue: issPageValues.POLICY_VEHICLES + }, { scenario: navigationScenarios.EDIT_VEHICLE, destinationIssPageValue: issPageValues.VEHICLE_SELECTION @@ -651,7 +655,7 @@ const routingTable = () => [ }, { scenario: navigationScenarios.EDIT_PREFERRED_SHOP, - destinationIssPageValue: issPageValues.TPA_SEARCH + destinationIssPageValue: issPageValues.PROVIDER_PREFERENCE }, { scenario: navigationScenarios.EDIT_CONTACT_DETAILS, diff --git a/src/store/index.js b/src/store/index.js index facfa026..e82cc2ab 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -220,6 +220,7 @@ export const useMainStore = defineStore({ 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, From ad0c9c9c2d48052240c3df6d8a0592f417994f77 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 22 Jan 2024 16:56:23 -0500 Subject: [PATCH 480/674] Updating contact info routing --- src/router/router-constants/routing-table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 22488935..03860dee 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -659,7 +659,7 @@ const routingTable = () => [ }, { scenario: navigationScenarios.EDIT_CONTACT_DETAILS, - destinationIssPageValue: issPageValues.CONTACT_DETAILS + destinationIssPageValue: issPageValues.POLICY_HOLDER_DETAILS }, { scenario: navigationScenarios.CLICKED_BACK, From 3278437d292e0969948b0e004d83363049cc7bc7 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 22 Jan 2024 17:01:01 -0500 Subject: [PATCH 481/674] tpa-conf styling and routing WIP --- .../tpa-confirmation/tpa-confirmation.vue | 136 ++++++++++++++++-- 1 file changed, 124 insertions(+), 12 deletions(-) diff --git a/src/layouts/tpa-confirmation/tpa-confirmation.vue b/src/layouts/tpa-confirmation/tpa-confirmation.vue index 9eabddb5..689a1e5f 100644 --- a/src/layouts/tpa-confirmation/tpa-confirmation.vue +++ b/src/layouts/tpa-confirmation/tpa-confirmation.vue @@ -12,17 +12,47 @@ class="mb-4" cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" /> - +
    + + +
    +
    + +
    + id="tpaConfirmationBodyOne" + ref="tpaConfirmationBodyOne" + :customText="tpaConfirmationBodyOne" /> + +
    + + + {{ getRouterLinkDisplayTextFromCopy(copy) }} + + + + +
    @@ -41,13 +71,16 @@ // Components import siteHeader from '@/iss-components/site-header/site-header.vue'; import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue'; -import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue'; import textBlock from '@/digital-components/text-block/text-block.vue'; import deductibleBox from '@/layouts/tpa-submit/deductible-box/deductible-box.vue'; // Supporting files -import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; +import { doesCopyContainRouterLink, + fetchCmsContentForPage, + splitCopyOnCMSPlaceHolder, + getRouterLinkRouteFromCopy, + getRouterLinkDisplayTextFromCopy } from '@/helpers/cms-content-helper'; import settleAllPromises from '@/helpers/layout-helper'; import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; @@ -63,7 +96,7 @@ export default { siteHeader, siteFooter, vehicleBanner, - siteSubHeader, + // siteSubHeader, textBlock, deductibleBox, // eslint-disable-next-line vue/no-reserved-component-names @@ -90,11 +123,12 @@ export default { return { mainStore }; }, data() { - const { companyName } = useMainStore().order.serviceLocation.provider; + const { companyName } = toTitleCase(useMainStore().order.serviceLocation.provider.companyName ?? ''); return { widget: { tpaConfirmation: 'TPAConfirmationContent', - orderDetails: 'OrderDetailsContent' + orderDetails: 'OrderDetailsContent', + contactCarrier: 'ContactCarrierContent' }, companyName, customValueMap: { @@ -103,9 +137,16 @@ export default { }; }, computed: { - tpaConfirmationBody() { + tpaConfirmationBodyOne() { return this.getCmsContent(this.widget.tpaConfirmation, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT) - .replaceAll('{custom:phoneNumber}', this.preferredShopPhoneNumber); + .replaceAll('{custom:phoneNumber}', this.preferredShopPhoneNumber) + .replaceAll('{custom:glassShop}', this.preferredShopName); + }, + tpaConfirmationBodyTwo() { + return this.getCmsContent(this.widget.tpaConfirmation, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2); + }, + preferredShopName() { + return toTitleCase(useMainStore().order.serviceLocation.provider.companyName); }, preferredShopPhoneNumber() { return this.toDisplayPhoneNumber(useMainStore().order.serviceLocation.provider.phoneNumber); @@ -121,6 +162,22 @@ export default { }, deductibleBoxValue() { return this.isVerified ? this.formatAmountInDollars(this.currentDeductible) : VERIFYING_COVERAGE; + }, + tpaConfirmationHeaderText() { + return this.getCmsContent('TPAConfirmationContent', 'HeaderText'); + }, + tpaConfirmationSubheaderText() { + return this.getCmsContent('TPAConfirmationContent', 'SubheaderText') + .replaceAll('{custom:glassShop}', this.preferredShopName); + }, + tpaConfirmationImage() { + return this.getCmsContent('TPAConfirmationContent', 'Image'); + }, + contactCarrierText() { + return this.getCmsContent(this.widget.contactCarrier, widgetFields.TEXT_BLOCK_WIDGET.TEXT); + }, + splitContactCarrierText() { + return this.splitCopyOnCMSPlaceHolder(this.contactCarrierText); } }, methods: @@ -150,10 +207,65 @@ export default { }, toDisplayPhoneNumber, toTitleCase, - formatAmountInDollars + formatAmountInDollars, + splitCopyOnCMSPlaceHolder, + doesCopyContainRouterLink, + getRouterLinkRouteFromCopy, + getRouterLinkDisplayTextFromCopy } }; From ad938af5d42f7c09277e6a1c26e6189766fdc51c Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 22 Jan 2024 17:10:19 -0500 Subject: [PATCH 482/674] Fixing safelite shop bug --- src/layouts/tpa-search/tpa-search.vue | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue index 25610da5..fbeb101d 100644 --- a/src/layouts/tpa-search/tpa-search.vue +++ b/src/layouts/tpa-search/tpa-search.vue @@ -354,7 +354,7 @@ export default { addressLine2 += zipCode; } - const addressLine1 = this.toTitleCase(provider?.address?.streetAddress); + const addressLine1 = toTitleCase(provider?.address?.streetAddress); const joinString = addressLine1.length > 0 && addressLine2.length > 0 ? ', ' : ''; return [addressLine1, addressLine2].join(joinString); }, @@ -390,7 +390,7 @@ export default { } }, getShopButtonDataFromProvider(provider) { - const cellNumber = this.toDisplayPhoneNumber(provider?.phoneNumber); + const cellNumber = toDisplayPhoneNumber(provider?.phoneNumber); const distance = provider?.distanceInMiles !== null && !Number.isNaN(parseFloat(provider?.distanceInMiles)) ? +provider.distanceInMiles.toFixed(1) : null; @@ -403,9 +403,7 @@ export default { buttonBodyCopy: `${this.getProviderAddress(provider)}
    ${cellNumber ?? ''}`, value: provider?.providerNumber ?? '' }; - }, - toDisplayPhoneNumber, - toTitleCase + } } }; From fe59bab8324ca60f3ab6c5e089863595ca6244fa Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 22 Jan 2024 17:15:11 -0500 Subject: [PATCH 483/674] Setting isSafeliteShop to true when appropriate --- src/layouts/tpa-search/tpa-search.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue index fbeb101d..449de6ca 100644 --- a/src/layouts/tpa-search/tpa-search.vue +++ b/src/layouts/tpa-search/tpa-search.vue @@ -376,6 +376,9 @@ export default { this.mapZipCode = this.zipCode; }, forwardButtonAction() { + if (this.selectedProviderIsSafeliteShop) { + useMainStore().updateIsSafeliteProvider(true); + } const scenario = this.selectedProviderIsSafeliteShop ? this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP : this.navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP; From 60ce38a9d5fd7a9d2eddc735b7c19d80d5b93bba Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 23 Jan 2024 10:05:58 -0500 Subject: [PATCH 484/674] change class from mt-5 to mt-4 --- src/layouts/schedule-page/schedule-page.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index acabea46..5a3fb0d4 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -9,7 +9,7 @@ + class="mt-4" /> @@ -102,6 +105,7 @@ import textBlock from '@/digital-components/text-block/text-block.vue'; import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue'; import reviewBlock from '@/layouts/tpa-submit/review-block/review-block.vue'; import deductibleBox from '@/layouts/tpa-submit/deductible-box/deductible-box.vue'; +import contactDetailsDrawer from '@/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue'; // Supporting files @@ -126,6 +130,7 @@ export default { reviewBlock, deductibleBox, siteFooter, + contactDetailsDrawer, // eslint-disable-next-line vue/no-reserved-component-names Form }, @@ -246,18 +251,20 @@ export default { ? this.navigationScenarios.EDIT_POLICY_VEHICLE : this.navigationScenarios.EDIT_VEHICLE; this.sections = [ - this.getSection(this.widget.subheader.vehicle, this.getVehicleLines, vehicleScenario), - this.getSection(this.widget.subheader.damage, this.getDamageLines, this.navigationScenarios.EDIT_DAMAGE), - this.getSection(this.widget.subheader.shop, this.getPreferredShopLines, this.navigationScenarios.EDIT_PREFERRED_SHOP), + this.getSection(this.widget.subheader.vehicle, this.getVehicleLines, () => this.navigate(vehicleScenario)), // eslint-disable-next-line max-len - this.getSection(this.widget.subheader.contactInfo, this.getContactInfoLines, this.navigationScenarios.EDIT_CONTACT_DETAILS) + this.getSection(this.widget.subheader.damage, this.getDamageLines, () => this.navigate(this.navigationScenarios.EDIT_DAMAGE)), + // eslint-disable-next-line max-len + this.getSection(this.widget.subheader.shop, this.getPreferredShopLines, () => this.navigate(this.navigationScenarios.EDIT_PREFERRED_SHOP)), + // eslint-disable-next-line max-len + this.getSection(this.widget.subheader.contactInfo, this.getContactInfoLines, this.openContactDetailsModal) ]; }, - getSection(widgetName, lines, scenario) { + getSection(widgetName, lines, onClick) { return { title: this.getCmsContent(widgetName, widgetFields.TEXT_BLOCK_WIDGET.TEXT), lines, - onClickEdit: () => this.navigate(scenario) + onClickEdit: onClick }; }, forwardButtonAction() { @@ -281,6 +288,9 @@ export default { getAnswersNullSafe(widgetName) { const rawAnswers = this.getCmsContent(widgetName, 'Answers'); return rawAnswers || []; + }, + openContactDetailsModal() { + this.$refs.contactDetailsDrawer.openModal(); } } }; From 53eab888d5c87e8baf694ac7166affdc344d9a72 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Wed, 24 Jan 2024 14:02:40 -0500 Subject: [PATCH 489/674] minor change --- .../contact-details-drawer.vue | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue index c46bce95..69e4cb95 100644 --- a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue +++ b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue @@ -117,12 +117,6 @@ export default { this.$emit('update-contact-details'); this.closeModal(); }, - openModal() { - this.modal.openModal(); - }, - closeModal() { - this.modal.closeModal(); - }, resetFormValues() { const { firstName, lastName, @@ -132,6 +126,12 @@ export default { this.lastName = lastName; this.emailAddress = emailAddress; this.phoneNumber = phoneNumber; + }, + openModal() { + this.modal.openModal(); + }, + closeModal() { + this.modal.closeModal(); } } }; From 9262b61b81b2b2384318bb7ac2e9de2e893894a4 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Wed, 24 Jan 2024 14:46:08 -0500 Subject: [PATCH 490/674] remove unneeded routing --- src/router/router-constants/routing-table.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 365a6dd0..2cded6f6 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -659,10 +659,6 @@ const routingTable = () => [ { scenario: navigationScenarios.CLICKED_FORWARD, destinationIssPageValue: issPageValues.WELCOME_PAGE - }, - { - scenario: navigationScenarios.REQUEST_CALLBACK, - destinationIssPageValue: issPageValues.BAILOUT_PAGE } ] }, From b6d4c768338ed6229b5412a11f2626815394aff8 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Wed, 24 Jan 2024 14:46:34 -0500 Subject: [PATCH 491/674] add order details body --- .../tpa-confirmation/tpa-confirmation.vue | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/layouts/tpa-confirmation/tpa-confirmation.vue b/src/layouts/tpa-confirmation/tpa-confirmation.vue index 8241710d..73e6c5cf 100644 --- a/src/layouts/tpa-confirmation/tpa-confirmation.vue +++ b/src/layouts/tpa-confirmation/tpa-confirmation.vue @@ -58,7 +58,15 @@ :customText="orderDetailsTitle" :marginTopSizeOverride="4" class="order-details" /> - + +
    From 7644a5c04e5d3488de6f731652faa14c7d088db8 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Thu, 25 Jan 2024 09:42:20 -0500 Subject: [PATCH 492/674] clean up --- .../tpa-confirmation/tpa-confirmation.vue | 64 ++++++------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/src/layouts/tpa-confirmation/tpa-confirmation.vue b/src/layouts/tpa-confirmation/tpa-confirmation.vue index 73e6c5cf..57f9e69d 100644 --- a/src/layouts/tpa-confirmation/tpa-confirmation.vue +++ b/src/layouts/tpa-confirmation/tpa-confirmation.vue @@ -6,7 +6,9 @@ @invalidSubmit="onInvalidSubmit">
    - +
    + class="small mb-4" /> - -
    +
    + :marginTopSizeOverride="4" /> + class="mb-4 small" /> @@ -110,7 +96,6 @@ export default { siteHeader, siteFooter, vehicleBanner, - // siteSubHeader, textBlock, deductibleBox, // eslint-disable-next-line vue/no-reserved-component-names @@ -137,25 +122,19 @@ export default { return { mainStore }; }, data() { - // const { companyName } = toTitleCase(useMainStore().order.serviceLocation.provider.companyName ?? ''); return { widget: { tpaConfirmation: 'TPAConfirmationContent', orderDetails: 'OrderDetailsContent', contactCarrier: 'ContactCarrierContent' } - // companyName, - // customValueMap: { - // glassShop: companyName, - // carrierPhoneNumber - // } }; }, computed: { tpaConfirmationBodyOne() { return this.getCmsContent(this.widget.tpaConfirmation, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT) - .replaceAll('{custom:phoneNumber}', this.preferredShopPhoneNumber) - .replaceAll('{custom:glassShop}', this.preferredShopName); + ?.replaceAll('{custom:phoneNumber}', this.preferredShopPhoneNumber) + ?.replaceAll('{custom:glassShop}', this.preferredShopName); }, tpaConfirmationBodyTwo() { return this.getCmsContent(this.widget.tpaConfirmation, widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2); @@ -187,16 +166,16 @@ export default { }, tpaConfirmationSubheaderText() { return this.getCmsContent('TPAConfirmationContent', 'SubheaderText') - .replaceAll('{custom:glassShop}', this.preferredShopName); + ?.replaceAll('{custom:glassShop}', this.preferredShopName); }, tpaConfirmationImage() { return this.getCmsContent('TPAConfirmationContent', 'Image'); }, contactCarrierText() { return this.getCmsContent(this.widget.contactCarrier, widgetFields.TEXT_BLOCK_WIDGET.TEXT) - .replaceAll('{custom:carrierPhoneNumber}', this.carrierPhoneNumber); + ?.replaceAll('{custom:carrierPhoneNumber}', this.carrierPhoneNumber); }, - // TODO: Replace with carrier number when account service is ready + // TODO: Replace with actual carrier number when account service is ready carrierPhoneNumber() { return '800-000-0000'; }, @@ -205,7 +184,7 @@ export default { } }, mounted() { - this.$refs.siteFooter.updateButtonText(`Go back to ${this.carrierName}`); + this.$refs.siteFooter?.updateButtonText(`Go back to ${this.carrierName}`); }, methods: { @@ -270,7 +249,6 @@ export default { margin-top: 0; :deep(p) { - color: $darker-gray; line-height: 1.5rem; font-size: 14px; @@ -286,11 +264,11 @@ export default { } #tpaConfirmationOrderDetailsTitle { - font-weight: 500; - line-height: 1.25rem; - color: $black; - margin-bottom: 1rem; - margin-top: 2rem; + font-weight: 500; + line-height: 1.5rem; + color: $black; + margin-bottom: 1rem; + margin-top: 2rem; } #contactCarrierText { From 110fdd7ba06892ee3e4b47828eb728ce0d99a27c Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 25 Jan 2024 12:01:23 -0500 Subject: [PATCH 493/674] adding unit tests for contact-details-drawer --- .../contact-details-drawer.spec.js.snap | 25 ++++ .../contact-details-drawer.spec.js | 134 ++++++++++++++++++ .../contact-details-drawer.vue | 8 +- src/layouts/tpa-submit/tpa-submit.spec.js | 10 ++ 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 src/layouts/tpa-submit/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap diff --git a/src/layouts/tpa-submit/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap b/src/layouts/tpa-submit/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap new file mode 100644 index 00000000..3b814991 --- /dev/null +++ b/src/layouts/tpa-submit/contact-details-drawer/__snapshots__/contact-details-drawer.spec.js.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`contact-details-drawer snapshot matches returns the initial data 1`] = ` +Object { + "emailAddress": "fred.tay@gmail.com", + "firstName": "Frederick", + "isModalOpened": false, + "lastName": "Taylor", + "phoneNumber": "606-009-2943", + "rules": Object { + "emailAddress": "email-required|email-address-format", + "firstName": "first-name-required", + "lastName": "last-name-required", + "phoneNumber": "phone-number-required|phone-number-format", + }, + "widget": Object { + "drawerFooter": "ContactDetailsDrawerFooterWidget", + "emailQuestion": "EmailQuestionWidget", + "firstNameQuestion": "FirstNameQuestionWidget", + "lastNameQuestion": "LastNameQuestionWidget", + "phoneNumberQuestion": "PhoneNumberQuestionWidget", + "title": "ContactDetailsDrawerHeaderWidget", + }, +} +`; diff --git a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js index e69de29b..e814af3d 100644 --- a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js +++ b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.spec.js @@ -0,0 +1,134 @@ +// Components +import { shallowMount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import contactDetailsDrawer from '@/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue'; + +// Supporting Files +import { getMountOptions } from '@/helpers/unit-test-helper.js'; +import { useMainStore } from '@/store'; + +function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRunAfterInitializingStore = () => {}) { + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + + const testingPinia = createTestingPinia({ + initialState: { + main: mainInitialState + } + }); + useMainStore(testingPinia); + methodToRunAfterInitializingStore(); + + mountOptions.global.plugins = [testingPinia]; + mountOptions.data = () => (initialData); + + const wrapper = shallowMount(contactDetailsDrawer, mountOptions); + return { wrapper }; +} + +describe('contact-details-drawer', () => { + test('snapshot matches returns the initial data', () => { + // Arrange + const firstName = 'Frederick'; + const lastName = 'Taylor'; + const emailAddress = 'fred.tay@gmail.com'; + const phoneNumber = '606-009-2943'; + const mainInitialState = { + order: { + contactInfo: { + firstName, + lastName, + emailAddress, + phoneNumber + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Assert + expect(wrapper.vm.$data).toMatchSnapshot(); + }); + test('renders modal', () => { + // Arrange + const wrapper = shallowMount(contactDetailsDrawer, getMountOptions()); + + // Act + const modal = wrapper.findComponent({ ref: 'contact-details-modal' }); + + // Assert + expect(modal.exists()).toBeTruthy(); + expect(modal.classes()).toContain('contact-details-drawer'); + }); + describe('method', () => { + describe('saveContactDetails', () => { + test.each([ + ['Sarah', 'Jones', 's.jones@gmail.com', '724-996-0909'], + [null, 'Jones', 's.jones@gmail.com', '724-996-0909'], + ['Sarah', null, 's.jones@gmail.com', '724-996-0909'], + ['Sarah', 'Jones', null, '724-996-0909'], + ['Sarah', 'Jones', 's.jones@gmail.com', null] + + ])( + 'when first name data "%p", last name "%p", email "%p", and phone number "%p", updateContactInfo called with expected', + (firstName, lastName, emailAddress, phoneNumber) => { + // Arrange + const mainInitialState = { + order: { + contactInfo: { + firstName: 'Frederick', + lastName: 'Taylor', + emailAddress: 'fred.tay@gmail.com', + phoneNumber: '606-009-2943' + } + } + }; + const initialData = { + firstName, lastName, emailAddress, phoneNumber + }; + const { wrapper } = getMountedComponent(mainInitialState, initialData); + + // Act + wrapper.vm.saveContactDetails(); + + // Assert + expect(wrapper.emitted()['update-contact-details']).toBeTruthy(); + expect(useMainStore().updateContactInfo).toBeCalledTimes(1); + expect(useMainStore().updateContactInfo).toBeCalledWith({ firstName, lastName, emailAddress, phoneNumber }); + } + ); + }); + test('resetFormValues sets data to expected values', () => { + // Arrange + const firstName = 'John'; + const lastName = 'Doe'; + const emailAddress = 'test@example.com'; + const phoneNumber = '123-456-1234'; + const mainInitialState = { + order: { + contactInfo: { + firstName, + lastName, + emailAddress, + phoneNumber + } + } + }; + const initialData = { + firstName: 'some name', + lastName: 'some end name', + emailAddress: 'email@what.com', + phoneNumber: '888' + }; + const { wrapper } = getMountedComponent(mainInitialState, initialData); + + // Act + wrapper.vm.resetFormValues(); + + // Assert + expect(wrapper.vm.firstName).toBe(firstName); + }); + }); +}); diff --git a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue index 69e4cb95..7fb5831e 100644 --- a/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue +++ b/src/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue @@ -6,12 +6,11 @@ :onModalClosedCallback="resetFormValues" class="contact-details-drawer" @isModalOpened="setModalStatus" - @footerButtonEvent="saveContactDetails"> + @footerButtonEvent="clickFooterButtonEvent"> diff --git a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.spec.js b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.spec.js index 8cf6c55b..523e10ba 100644 --- a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.spec.js +++ b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.spec.js @@ -1,87 +1,34 @@ -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { shallowMount } from '@vue/test-utils'; +import { getMountOptions } from '@/helpers/unit-test-helper.js'; -import paymentMethodListButton from "@/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button"; +// eslint-disable-next-line max-len +import paymentMethodListButton from '@/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue'; const testConstants = { images: { - A: "imageA", - B: "imageB", - NONE: null, + A: 'imageA', + B: 'imageB', + NONE: null }, names: { - A: "nameA", - B: "nameB", + A: 'nameA', + B: 'nameB' }, content: { - withInline: "Button text with {custom:inlineImage} inline.", - noInline: "Button text with no inline", + withInline: 'Button text with {custom:inlineImage} inline.', + noInline: 'Button text with no inline' }, }; let cmsContent; -describe("Payment Method Question", () => { - beforeEach(() => { - cmsContent = {}; - }); - - describe("Side image", () => { - it("Renders side image if image is present and not inline", () => { - // Arrange - const props = generateDefaultProps(); - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - const showSideImage = wrapper.vm.shouldDisplaySideImage; - - expect(showSideImage).toBe(true); - }); - - it("Does not render side image if no image is present", () => { - // Arrange - let props = generateDefaultProps(); - - props.buttonImage = testConstants.images.NONE; - - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - const showSideImage = wrapper.vm.shouldDisplaySideImage; - - expect(showSideImage).toBe(false); - }); - - it("Does not render side image if inline", () => { - // Arrange - let props = generateDefaultProps(); - - props.buttonLabel = testConstants.content.withInline; - props.altText = testConstants.content.withInline; - - const { wrapper } = setupMocks({ - propsData: props, - }); - - // Act - const showSideImage = wrapper.vm.shouldDisplaySideImage; - - expect(showSideImage).toBe(false); - }); - }); -}); - function generateDefaultProps() { return { buttonLabel: testConstants.noInline, altText: testConstants.noInline, - groupName: "payment-method", + groupName: 'payment-method', value: testConstants.names.A, - buttonImage: testConstants.images.A, + buttonImage: testConstants.images.A }; } @@ -91,9 +38,9 @@ function setupMocks(customMountOptions) { const mockMixin = { methods: { getCmsContent: jest.fn((widgetName, cmsFieldName) => { - return cmsContent?.[widgetName]?.[cmsFieldName] ?? ""; - }), - }, + return cmsContent?.[widgetName]?.[cmsFieldName] ?? ''; + }) + } }; mountOptions.global.mixins = [mockMixin]; @@ -102,3 +49,57 @@ function setupMocks(customMountOptions) { wrapper.vm.setCmsContent = jest.fn(); return { wrapper }; } + +describe('Payment Method Question', () => { + beforeEach(() => { + cmsContent = {}; + }); + + describe('Side image', () => { + it('Renders side image if image is present and not inline', () => { + // Arrange + const props = generateDefaultProps(); + const { wrapper } = setupMocks({ + propsData: props + }); + + // Act + const showSideImage = wrapper.vm.shouldDisplaySideImage; + + expect(showSideImage).toBe(true); + }); + + it('Does not render side image if no image is present', () => { + // Arrange + const props = generateDefaultProps(); + + props.buttonImage = testConstants.images.NONE; + + const { wrapper } = setupMocks({ + propsData: props + }); + + // Act + const showSideImage = wrapper.vm.shouldDisplaySideImage; + + expect(showSideImage).toBe(false); + }); + + it('Does not render side image if inline', () => { + // Arrange + const props = generateDefaultProps(); + + props.buttonLabel = testConstants.content.withInline; + props.altText = testConstants.content.withInline; + + const { wrapper } = setupMocks({ + propsData: props + }); + + // Act + const showSideImage = wrapper.vm.shouldDisplaySideImage; + + expect(showSideImage).toBe(false); + }); + }); +}); diff --git a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue index 2763f1af..871f8ba7 100644 --- a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue +++ b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue @@ -1,8 +1,8 @@ From 25c2bc33070c3bf77c3821694b04b7f19cb50f29 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 12 Feb 2024 11:56:45 -0500 Subject: [PATCH 528/674] Sending ITAC and no comp TPA requests to bailout --- src/layouts/coverage-statement/coverage-statement.vue | 4 ++-- src/router/router-constants/routing-table.js | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 8d455e00..fa6f17c3 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -386,9 +386,9 @@ export default { { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else { - this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.TPANotEnabled()); + this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); this.$router.navigate( - navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED, + navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, this.$route, {}, { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 03860dee..0badb2e7 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -509,11 +509,7 @@ const routingTable = () => [ destinationIssPageValue: issPageValues.SERVICE_LOCATION }, { - scenario: navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED, - destinationIssPageValue: issPageValues.TPA_SEARCH - }, - { - scenario: navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED, + scenario: navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, destinationIssPageValue: issPageValues.BAILOUT_PAGE }, { From 53393721c67927536023c411af705828411324c9 Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Mon, 12 Feb 2024 13:39:11 -0500 Subject: [PATCH 529/674] SSR-1064 small updates --- .../payment-method-list-button.vue | 2 +- src/layouts/payment-method/payment-method.vue | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue index 871f8ba7..0f834cbc 100644 --- a/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue +++ b/src/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button.vue @@ -117,7 +117,7 @@ export default { span { &.small { - font-size: 0.75rem; + font-size: $font-size-xsm; color: $gray-550; } } diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 57e425f3..10ebc609 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -53,14 +53,10 @@ import { useMainStore } from '@/store'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import paymentMethods from '@/constants/payment-method-constants'; import globalRules from '@/constants/global-rules'; -import { Form, defineRule } from 'vee-validate'; +import { Form } from 'vee-validate'; -import { required } from '@/helpers/validation-rules'; -import errorMessages from '@/constants/error-messages'; import { AppointmentTypeStrings } from '@/constants/schedule-constants'; -defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED)); - export default { name: 'payment-method', components: { @@ -210,9 +206,6 @@ export default { this.$refs.siteFooter.updateButtonText(newValue); }, async forwardButtonAction() { - // Multiple paths based on payment - console.log('forward button hit...'); - await useMainStore().savePaymentMethodChoice(this.paymentMethod); } } From 7c946ab114d8f7ef2c4d6934d045c5b6fc6bd49b Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 14 Feb 2024 09:30:43 -0500 Subject: [PATCH 530/674] lint fix --- src/layouts/welcome-page/welcome-page.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layouts/welcome-page/welcome-page.spec.js b/src/layouts/welcome-page/welcome-page.spec.js index 38733d63..efd1c924 100644 --- a/src/layouts/welcome-page/welcome-page.spec.js +++ b/src/layouts/welcome-page/welcome-page.spec.js @@ -69,7 +69,7 @@ function setupMocks({ } }; - mountOptionsMockData = { + const mockDataMountOptions = { ...mountOptionsMockData, router: { navigate: jest.fn() @@ -81,7 +81,7 @@ function setupMocks({ settleAllPromises.mockImplementation(() => apiPromise); fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); - const mountOptions = getMountOptions(mountOptionsMockData); + const mountOptions = getMountOptions(mockDataMountOptions); const wrapper = shallowMount(welcomePage, mountOptions); From 51e612d50a207a52179448ccf23fc5b0562855a7 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 14 Feb 2024 14:25:52 -0500 Subject: [PATCH 531/674] validation updates. --- src/constants/error-messages.js | 4 ++ src/layouts/welcome-page/welcome-page.vue | 75 +++++++++++++++++++---- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index 0c8d4719..39543b5f 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -32,17 +32,21 @@ const errorMessages = Object.freeze({ OPTION_REQUIRED: 'Please select an option', VEHICLE_REQUIRED: 'Please select a vehicle', POLICY_NUMBER_REQUIRED: 'Please enter your policy number', + POLICY_NUMBER_FORMAT: 'Please enter an alpha-numeric string', PHONE_NUMBER_REQUIRED: 'Please enter phone number', PHONE_NUMBER_FORMAT: 'Please enter your phone number. The format must be ###-###-####', POLICY_ZIP_REQUIRED: 'Please enter your policy ZIP', POLICY_ZIP_FORMAT: 'Please enter a valid ZIP', LOSS_CAUSE_REQUIRED: 'Please enter loss cause', LOSS_CITY_REQUIRED: 'Please enter a city', + LOSS_CITY_FORMAT: 'Please enter only alpha characters', LOSS_STATE_REQUIRED: 'Please select an option', LOSS_DATE_REQUIRED: 'Please select a date. Format must be MM/DD/YYYY and the date must be not in the future', DAMAGE_DATE_REQUIREMENT: 'Damage date must be within the past 10 years', + DAMAGE_DATE_NO_FUTURE_DATE: + 'Damage date may not be in the future', DAMAGE_OPTION_REQUIRED: 'Please select an option', POLICYHOLDER_FIRST_NAME_REQUIRED: 'Please enter the policyholder first name', diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 77a60a5f..b9cac195 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -85,7 +85,7 @@ cmsWidgetName="PhoneNumberQuestion" :validationRules="rules.phoneNumber" isRequired - mask="###-###-####" + :mask="mask" disableAutoFill />
    @@ -153,7 +153,15 @@ id="welcomeFooter" class="row position-sticky top-100">
    + { return true; }); +defineRule('loss-date-lt-tomorrow', (value) => { + const lossDate = new Date(Date.parse(`${value}T00:00:00`)); + const today = new Date(); + const tomorrow = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0, 0); + if (lossDate >= tomorrow) { + return errorMessages.DAMAGE_DATE_NO_FUTURE_DATE; + } + + return true; +}); export default { name: 'welcome-page', components: { siteHeader, siteSubHeader, + alert, buttonQuestion, textboxQuestion, dropdownQuestion, @@ -260,15 +288,16 @@ export default { data() { return { welcomePageModel: this.getWelcomePageModelFromStore(), + displayInvalidZipAlert: false, duplicates: [], rules: { - policyNumber: 'policy-number-required', + policyNumber: 'policy-number-required|policy-number-format', policyZip: 'policy-zip-required|policy-zip-format', - lossDate: 'loss-date-required|loss-date-gt-10-years', + lossDate: 'loss-date-required|loss-date-gt-10-years|loss-date-lt-tomorrow', damageOption: 'damage-option-required', phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`, email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`, - lossCity: 'loss-city-required', + lossCity: 'loss-city-required|loss-city-format', lossState: 'loss-state-required' } }; @@ -319,20 +348,42 @@ export default { }, maxCoverageLookupAttemptsReached() { return this.mainStore.applicationUser.coverageLookupAttempts >= 11; + }, + mask() { + return { + mask: 'x##-###-####', + tokens: { + x: { + pattern: /[2-9]/ + } + } + }; } }, methods: { async forwardButtonAction() { - this.mainStore.updatePolicyData(this.welcomePageModel); - await this.mainStore.getDuplicateReferrals() - .then(() => {}, () => {}) - .finally(async () => { - if (this.isCoverageEnabled && !this.maxCoverageLookupAttemptsReached) { - await this.mainStore.getCoveragePolicyInfo()?.then(() => {}, () => {}); + console.log('zip code...'); + console.log(this.welcomePageModel.policyZipCode); + await this.mainStore.validateZip({ zip: this.welcomePageModel.policyZipCode }) + .then(async (zipInfo) => { + if (zipInfo?.data?.isValid === true) { + this.mainStore.updatePolicyData(this.welcomePageModel); + await this.mainStore.getDuplicateReferrals() + .then(() => {}, () => {}) + .finally(async () => { + if (this.isCoverageEnabled && !this.maxCoverageLookupAttemptsReached) { + await this.mainStore.getCoveragePolicyInfo()?.then(() => {}, () => {}); + } else { + this.mainStore.order.policy.policyLookupSuccessful = false; + } + return this.navigateForward(); + }); } else { - this.mainStore.order.policy.policyLookupSuccessful = false; + // set manual error message + console.log('zip invalid...'); + this.displayInvalidZipAlert = true; + return this.$refs.siteFooter.removeLoader(); } - this.navigateForward(); }); }, navigateForward() { From 1580a7761a6b2d20b20fc44f3ae5879105a13dfb Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Thu, 15 Feb 2024 09:51:46 -0500 Subject: [PATCH 532/674] SSR-1063 initial routing changes --- src/router/router-constants/navigation-scenarios.js | 3 +++ src/router/router-constants/routing-table.js | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index f71a452a..1406498e 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -89,6 +89,9 @@ const navigationScenarios = Object.freeze({ CLICKED_SERVICE_PACKAGE_EDIT: 'CLICKED_SERVICE_PACKAGE_EDIT', CLICKED_VEHICLE_EDIT: 'CLICKED_VEHICLE_EDIT', + // Payment + CLICKED_PAY_NOW: 'CLICKED_PAY_NOW', + // Bailout CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' }); diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 0badb2e7..30b3cf84 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -609,6 +609,10 @@ const routingTable = () => [ { scenario: navigationScenarios.CLICKED_FORWARD, destinationIssPageValue: issPageValues.ORDER_CONFIRMATION + }, + { + scenario: navigationScenarios.CLICKED_PAY_NOW, + destinationIssPageValue: issPageValues.PAYMENT_PAGE } ] }, @@ -616,7 +620,7 @@ const routingTable = () => [ issPageValue: issPageValues.PAYMENT_PAGE, maps: [ { - scenario: navigationScenarios.CLICKED_BACK, + scenario: navigationScenarios.PAYMENT_METHOD, destinationIssPageValue: issPageValues.REVIEW_PAGE }, { From 3c90f560be781e290e64036ff580d67959870842 Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Thu, 15 Feb 2024 10:05:25 -0500 Subject: [PATCH 533/674] SSR-1063 forward button nav logic --- src/layouts/payment-method/payment-method.vue | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 10ebc609..808c27a7 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -207,6 +207,18 @@ export default { }, async forwardButtonAction() { await useMainStore().savePaymentMethodChoice(this.paymentMethod); + + if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) { + this.$router.navigate( + this.navigationScenarios.CLICKED_FORWARD, + this.$route + ); + } else { + this.$router.navigate( + this.navigationScenarios.CLICKED_PAY_NOW, + this.$route + ); + } } } }; From 421de749f4e1d18424a16cf5468f45353c8c8dfb Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Thu, 15 Feb 2024 12:39:10 -0500 Subject: [PATCH 534/674] SSR-1063 needed to add baseFormMixin to payment-method page --- src/layouts/payment-method/payment-method.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 808c27a7..71c1579c 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -41,6 +41,7 @@ diff --git a/src/router/router-constants/externalUrl-values.js b/src/router/router-constants/externalUrl-values.js new file mode 100644 index 00000000..4a44e9c0 --- /dev/null +++ b/src/router/router-constants/externalUrl-values.js @@ -0,0 +1,5 @@ +const externalUrls = { + SAFELITE_HOP: process.env.VUE_APP_SAFELITE_HOP +}; + +export default externalUrls; diff --git a/src/store/index.js b/src/store/index.js index c8623193..1b963902 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2144,6 +2144,13 @@ export const useMainStore = defineStore({ 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 + }); } }, diff --git a/vue.config.js b/vue.config.js index dcc30a25..24f2d771 100644 --- a/vue.config.js +++ b/vue.config.js @@ -2,6 +2,7 @@ process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io'; process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0'; +process.env.VUE_APP_SAFELITE_HOP = 'https://sv2-safelitehop-sys.safelite.com/fmgCheckoutEmbedded.aspx'; // GA & GTM // NOTE: Using the old ISS site GTM Cotnainer ID for now, will create a new one soon. From e185e8a63809248bf9cf41482e344e5431efe560 Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Tue, 20 Feb 2024 14:21:05 -0500 Subject: [PATCH 541/674] SSR-1063 environment variable updates --- azure-pipelines.yml | 4 ++++ src/layouts/payment-page/payment-page.vue | 2 +- vue.release.config.js | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3e06d0dc..8843c001 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -85,6 +85,7 @@ stages: __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) + __VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__) indexDeployVariables: __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) @@ -135,6 +136,7 @@ stages: __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) + __VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__) indexDeployVariables: __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) @@ -185,6 +187,7 @@ stages: __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) + __VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__) indexDeployVariables: __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) @@ -235,6 +238,7 @@ stages: __VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__) __VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__) __VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__) + __VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__) indexDeployVariables: __VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__) __VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__) diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index 86f9089d..15e43070 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -171,7 +171,7 @@ import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store'; import iframeResize from '../../../node_modules/iframe-resizer/js/iframeResizer.js'; -import externalUrls from '@/router/router-constants/externalUrl-values'; +import externalUrls from '@/router/router-constants/externalUrl-values.js'; import widgetFields from '@/constants/cms-widget-fields.js'; import paymentMethods from '@/constants/payment-method-constants'; import { AppointmentTypeStrings } from '@/constants/schedule-constants'; diff --git a/vue.release.config.js b/vue.release.config.js index c3c79a75..2cfed6dd 100644 --- a/vue.release.config.js +++ b/vue.release.config.js @@ -1,6 +1,7 @@ process.env.VUE_APP_CONSUMER_CF_DISTRO = "__VUE_APP_CONSUMER_CF_DISTRO__"; process.env.VUE_APP_CURRENT_ENVIRONMENT = "__VUE_APP_CURRENT_ENVIRONMENT__"; process.env.VUE_APP_GOOGLE_PLACES_API_KEY = "__VUE_APP_GOOGLE_PLACES_API_KEY__"; +process.env.VUE_APP_SAFELITE_HOP = "__VUE_APP_SAFELITE_HOP__"; // GA & GTM process.env.VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY = "__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__"; From f146d193d50618078f2c0507c54521d687f285e3 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 20 Feb 2024 15:15:45 -0500 Subject: [PATCH 542/674] Match Figma Spacer mt-4 Spacer mb-5 Between Header and SubHeader: Spacer mt-2 24px (1.5rem) Padding on sides. Cumulative between container-fluid and px-3 --- src/iss-components/site-sub-header/site-sub-header.vue | 3 ++- src/layouts/payment-method/payment-method.vue | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/iss-components/site-sub-header/site-sub-header.vue b/src/iss-components/site-sub-header/site-sub-header.vue index a26ea95f..2ea8340f 100644 --- a/src/iss-components/site-sub-header/site-sub-header.vue +++ b/src/iss-components/site-sub-header/site-sub-header.vue @@ -16,7 +16,7 @@
    + :class="[justifySubheader, subHeaderClasses]">

    @@ -50,6 +50,7 @@ export default { justification: String, stripRteStyle: Boolean, subContentProperty: String, + subHeaderClasses: String, subTextClasses: String }, emits: ['click-event'], diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 10ebc609..2beb7322 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -12,8 +12,9 @@ cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="false" /> + class="mb-5 mt-4 px-3" + cmsWidgetName="SiteSubHeaderWidget" + subHeaderClasses="mt-2" />


    From ea29ef0c7318a69e9d511f4e4c2fb500eb150431 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 20 Feb 2024 16:56:31 -0500 Subject: [PATCH 543/674] Add billToAccountNumber --- src/store/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/store/index.js b/src/store/index.js index c8623193..2b35d46d 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -776,6 +776,7 @@ export const useMainStore = defineStore({ 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, @@ -838,6 +839,7 @@ export const useMainStore = defineStore({ endDate, shopAppointmentType, applicationName: applicationConfig.APPLICATION_NAME, + billToAccountNumber: this.issConfig.parentAccountNumber.toString(), // TODO: MAKE THIS REAL parentAccountNumber: this.issConfig.parentAccountNumber, // this.payment.parentAccountNumber, carId: vehicle.carId, lineItems, From 231c8baa093949c6e59c9d4642fdd7698801b49a Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Wed, 21 Feb 2024 09:04:01 -0500 Subject: [PATCH 544/674] SSR-1063 routing typo fix --- src/router/router-constants/routing-table.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 30b3cf84..df960f77 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -620,8 +620,8 @@ const routingTable = () => [ issPageValue: issPageValues.PAYMENT_PAGE, maps: [ { - scenario: navigationScenarios.PAYMENT_METHOD, - destinationIssPageValue: issPageValues.REVIEW_PAGE + scenario: navigationScenarios.CLICKED_BACK, + destinationIssPageValue: issPageValues.PAYMENT_METHOD }, { scenario: navigationScenarios.CLICKED_FORWARD, From ceb48a92407daf8925ea262cdcd42f68d82acb3b Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 21 Feb 2024 15:43:21 -0500 Subject: [PATCH 545/674] Set some variables to be more accurate for testing --- src/constants/application-config.js | 4 +++- src/store/index.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/constants/application-config.js b/src/constants/application-config.js index 06fd28b5..fb91d504 100644 --- a/src/constants/application-config.js +++ b/src/constants/application-config.js @@ -16,7 +16,9 @@ const applicationConfig = Object.freeze({ CLIENTTAG_QUERYSTRING: 'ClientTag', GOOGLE_PLACES_API_KEY: process.env.VUE_APP_GOOGLE_PLACES_API_KEY, ISS_DEV_CMS_DOMAIN: 'https://digitalisscms.dev.safelite.io', - CASH_PARENT_ACCOUNT_NUMBER: 167132 + CASH_PARENT_ACCOUNT_NUMBER: 167132, + ITAC_FAIR_AND_REASONABLE_BILLTO: '214616', // Lib Mutal FnR BillTo + ITAC_CASH_BILLTO: '283393' // Lib Mutal ITAC Cash BillTo }); export default applicationConfig; diff --git a/src/store/index.js b/src/store/index.js index 2b35d46d..117b37bf 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -839,7 +839,7 @@ export const useMainStore = defineStore({ endDate, shopAppointmentType, applicationName: applicationConfig.APPLICATION_NAME, - billToAccountNumber: this.issConfig.parentAccountNumber.toString(), // TODO: MAKE THIS REAL + 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, From 906374126859b4f1fa57226ddf5c87cfa45554a6 Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Wed, 21 Feb 2024 16:23:26 -0500 Subject: [PATCH 546/674] SSR-1063 hop payment method constants --- src/constants/payment-method-constants.js | 8 +++- .../payment-method/payment-method.spec.js | 2 +- src/layouts/payment-method/payment-method.vue | 2 +- src/layouts/payment-page/payment-page.spec.js | 16 +++---- src/layouts/payment-page/payment-page.vue | 44 +++++++------------ src/router/index.js | 8 ++++ src/store/index.js | 2 +- src/store/store.spec.js | 2 +- vue.config.js | 2 +- 9 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/constants/payment-method-constants.js b/src/constants/payment-method-constants.js index 0af1a4de..48aa5008 100644 --- a/src/constants/payment-method-constants.js +++ b/src/constants/payment-method-constants.js @@ -1,3 +1,9 @@ +const hopPaymentMethods = Object.freeze({ + CREDIT_CARD: 'cc', + PAYPAL: 'pp', + AFTERPAY: 'ap' +}); + const paymentMethods = Object.freeze({ NONE: null, PAY_AT_TIME_OF_SERVICE: 'PayAtTimeOfService', @@ -6,4 +12,4 @@ const paymentMethods = Object.freeze({ AFTERPAY: 'Afterpay' }); -export default paymentMethods; +export { hopPaymentMethods, paymentMethods }; diff --git a/src/layouts/payment-method/payment-method.spec.js b/src/layouts/payment-method/payment-method.spec.js index dc31f064..01e06a1e 100644 --- a/src/layouts/payment-method/payment-method.spec.js +++ b/src/layouts/payment-method/payment-method.spec.js @@ -5,7 +5,7 @@ import paymentMethod from '@/layouts/payment-method/payment-method.vue'; import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { useMainStore } from '@/store'; -import paymentMethods from '@/constants/payment-method-constants'; +import { paymentMethods } from '@/constants/payment-method-constants'; function setupMocks() { const mountOptions = getMountOptions(); diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 71c1579c..b08cb685 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -52,7 +52,7 @@ import paymentMethodQuestion from '@/layouts/payment-method/payment-method-quest import settleAllPromises from '@/helpers/layout-helper'; import { useMainStore } from '@/store'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; -import paymentMethods from '@/constants/payment-method-constants'; +import { paymentMethods } from '@/constants/payment-method-constants'; import globalRules from '@/constants/global-rules'; import { Form } from 'vee-validate'; diff --git a/src/layouts/payment-page/payment-page.spec.js b/src/layouts/payment-page/payment-page.spec.js index c7e66af8..1b46819f 100644 --- a/src/layouts/payment-page/payment-page.spec.js +++ b/src/layouts/payment-page/payment-page.spec.js @@ -5,7 +5,7 @@ import payment from '@/layouts/payment-page/payment-page.vue'; import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper'; import { useMainStore } from '@/store'; -import paymentMethods from '@/constants/payment-method-constants' +import { paymentMethods, hopPaymentMethods } from '@/constants/payment-method-constants.js'; // Constants const parts = { @@ -305,7 +305,7 @@ describe('payment-page.vue', () => { describe('payment type mapping', () => { describe('getPaymentType', () => { - test('Maps AFTERPAY -> ap', () => { + test('Maps AFTERPAY -> hopPaymentMethods.AFTERPAY', () => { // Arrange useMainStore().order.payment.payInAdvanceType = paymentMethods.AFTERPAY; const wrapper = setupMocks({}); @@ -314,10 +314,10 @@ describe('payment-page.vue', () => { const mapped = wrapper.vm.getPaymentType(); // Assert - expect(mapped).toBe('ap'); + expect(mapped).toBe(hopPaymentMethods.AFTERPAY); }); - test('Maps CREDIT_CARD -> cc', () => { + test('Maps CREDIT_CARD -> hopPaymentMethods.CREDIT_CARD', () => { // Arrange useMainStore().order.payment.payInAdvanceType = paymentMethods.CREDIT_CARD; const wrapper = setupMocks({}); @@ -326,10 +326,10 @@ describe('payment-page.vue', () => { const mapped = wrapper.vm.getPaymentType(); // Assert - expect(mapped).toBe('cc'); + expect(mapped).toBe(hopPaymentMethods.CREDIT_CARD); }); - test('Maps PAYPAL -> pp', () => { + test('Maps PAYPAL -> hopPaymentMethods.PAYPAL', () => { // Arrange useMainStore().order.payment.payInAdvanceType = paymentMethods.PAYPAL; const wrapper = setupMocks({}); @@ -338,7 +338,7 @@ describe('payment-page.vue', () => { const mapped = wrapper.vm.getPaymentType(); // Assert - expect(mapped).toBe('pp'); + expect(mapped).toBe(hopPaymentMethods.PAYPAL); }); test('Maps other values to self', () => { @@ -362,7 +362,7 @@ describe('payment-page.vue', () => { // Act const preVal = wrapper.vm.isPaypal; - wrapper.vm.paymentType = 'pp'; + wrapper.vm.paymentType = hopPaymentMethods.PAYPAL; await wrapper.vm.$nextTick(); const postVal = wrapper.vm.isPaypal; diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index 15e43070..da98875f 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -23,7 +23,7 @@ @@ -170,11 +170,11 @@ import settleAllPromises from '@/helpers/layout-helper'; import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store'; -import iframeResize from '../../../node_modules/iframe-resizer/js/iframeResizer.js'; +import iframeResize from '@/../node_modules/iframe-resizer/js/iframeResizer.js'; import externalUrls from '@/router/router-constants/externalUrl-values.js'; import widgetFields from '@/constants/cms-widget-fields.js'; -import paymentMethods from '@/constants/payment-method-constants'; -import { AppointmentTypeStrings } from '@/constants/schedule-constants'; +import { hopPaymentMethods, paymentMethods } from '@/constants/payment-method-constants.js'; +import { AppointmentTypeStrings } from '@/constants/schedule-constants.js'; export default { name: 'payment-page', @@ -282,7 +282,7 @@ export default { return ''; }, isPaypal() { - if (this.paymentType === 'pp') { + if (this.paymentType === hopPaymentMethods.PAYPAL) { return true; } return false; @@ -359,7 +359,6 @@ export default { return items[1]; } } - //this.backButtonAction(); return undefined; }, getInvoiceNumber() { @@ -367,42 +366,31 @@ export default { if (workOrderNumber) { return workOrderNumber.replace('-', ''); } - //this.backButtonAction(); return undefined; }, getAddress1() { - return useMainStore().order.serviceLocation.address - ? useMainStore().order.serviceLocation.address - : useMainStore().order.serviceLocation.provider.address.streetAddress; + return useMainStore().order.serviceLocation.address ?? useMainStore().order.serviceLocation.provider.address.streetAddress; }, getAddress2() { - return useMainStore().order.serviceLocation.address2 - ? useMainStore().order.serviceLocation.address2 - : null; + return useMainStore().order.serviceLocation.address2; }, getCity() { - return useMainStore().order.serviceLocation.city - ? useMainStore().order.serviceLocation.city - : useMainStore().order.serviceLocation.provider.address.city; + return useMainStore().order.serviceLocation.city ?? useMainStore().order.serviceLocation.provider.address.city; }, getState() { - return useMainStore().order.serviceLocation.state - ? useMainStore().order.serviceLocation.state - : useMainStore().order.serviceLocation.provider.address.state; + return useMainStore().order.serviceLocation.state ?? useMainStore().order.serviceLocation.provider.address.state; }, getZipCode() { - return useMainStore().order.serviceLocation.zipCode - ? useMainStore().order.serviceLocation.zipCode - : useMainStore().order.serviceLocation.provider.address.zipCode; + return useMainStore().order.serviceLocation.zipCode ?? useMainStore().order.serviceLocation.provider.address.zipCode; }, getPaymentType() { switch (useMainStore().order.payment.payInAdvanceType) { case paymentMethods.AFTERPAY: - return 'ap'; + return hopPaymentMethods.AFTERPAY; case paymentMethods.CREDIT_CARD: - return 'cc'; + return hopPaymentMethods.CREDIT_CARD; case paymentMethods.PAYPAL: - return 'pp'; + return hopPaymentMethods.PAYPAL; default: return useMainStore().payment.payInAdvanceType; } @@ -428,9 +416,9 @@ export default { if (iframe) { iframe.onload = () => { if (iframe.contentWindow) { - if (this.paymentType === 'cc') { + if (this.paymentType === hopPaymentMethods.CREDIT_CARD) { iframe.contentWindow.postMessage('CreditCardChosen', '*'); - } else if (this.paymentType === 'ap') { + } else if (this.paymentType === hopPaymentMethods.AFTERPAY) { iframe.contentWindow.postMessage('afterpay', '*'); } } @@ -466,8 +454,6 @@ export default { }, forwardButtonAction() { this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route); - }, - navigateForward() { } } }; diff --git a/src/router/index.js b/src/router/index.js index bef88b03..4cd2dc45 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -129,6 +129,14 @@ router.beforeEach(async (to, from) => { showIssLoadingModal(true); } + const isInIframe = fromQueryPage === IssPageValues.PAYMENT_PAGE; + if (isInIframe) { + // need to set window.top.location.href directly when navigating out of an iframe + // especially when navigating with browser buttons + const newUrl = `${window.top.location.origin}${to.href}`; + window.top.location.href = newUrl; + } + const store = useMainStore(); // Prevent navigating backwards if we enter a bailout that we are not allowed to go back on if (store.isBailout && from.name === IssPageValues.BAILOUT_PAGE && to.name !== 'root' && to.name !== IssPageValues.CONTACT_CONFIRMATION diff --git a/src/store/index.js b/src/store/index.js index 1b963902..3daecdfc 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -13,7 +13,7 @@ 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 { paymentMethods } from '@/constants/payment-method-constants'; const storeId = 'main'; diff --git a/src/store/store.spec.js b/src/store/store.spec.js index 108b5900..98f2fd09 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -3,7 +3,7 @@ import { useMainStore } from '@/store/index.js'; import globalMethods from '@/global-methods.js'; import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from '@/helpers/data-generation.js'; import coverageStatuses from '@/constants/coverage-statuses.js'; -import paymentMethods from '@/constants/payment-method-constants'; +import { paymentMethods } from '@/constants/payment-method-constants'; import { endpoints } from '@/constants/endpoints'; import { AppointmentTypeStrings } from '@/constants/schedule-constants'; diff --git a/vue.config.js b/vue.config.js index 24f2d771..0a7711e6 100644 --- a/vue.config.js +++ b/vue.config.js @@ -2,7 +2,7 @@ process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io'; process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0'; -process.env.VUE_APP_SAFELITE_HOP = 'https://sv2-safelitehop-sys.safelite.com/fmgCheckoutEmbedded.aspx'; +process.env.VUE_APP_SAFELITE_HOP = 'https://iss-hop-sys.glassclaim.com/fmgCheckoutEmbedded.aspx'; // GA & GTM // NOTE: Using the old ISS site GTM Cotnainer ID for now, will create a new one soon. From 88eeaef09d06ea52602378795be59a0aae9f9988 Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Thu, 22 Feb 2024 09:42:20 -0500 Subject: [PATCH 547/674] SSR-1063 minor updates --- src/layouts/payment-page/payment-page.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index da98875f..8aa03d52 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -23,8 +23,8 @@
    @@ -155,7 +155,7 @@ - + + + From 16b8691d42c7a19cdc11e19f662bc7864e5636bd Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 27 Feb 2024 10:33:30 -0500 Subject: [PATCH 560/674] auto-save formatting only to prevent un needed compare in the actual PR later. --- src/layouts/payment-page/payment-page.vue | 386 ++++++++++++++++------ 1 file changed, 293 insertions(+), 93 deletions(-) diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index 36f072c6..c37fde79 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -38,71 +38,192 @@
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    From a97fe72e5e87bb23d16985e3876591ba010ef27d Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Tue, 27 Feb 2024 16:46:34 -0500 Subject: [PATCH 563/674] SSR-1081 handling payment return info from hop --- src/constants/query-strings.js | 17 +- src/constants/web-storage-constants.js | 5 + src/helpers/querystring-helper.js | 11 ++ src/layouts/payment-page/payment-page.vue | 8 +- src/layouts/payment-return/payment-return.vue | 145 ++++++++++++++++++ .../router-constants/navigation-scenarios.js | 3 + src/router/router-constants/routing-table.js | 17 ++ src/store/index.js | 79 ++++++++-- 8 files changed, 262 insertions(+), 23 deletions(-) create mode 100644 src/constants/web-storage-constants.js create mode 100644 src/helpers/querystring-helper.js create mode 100644 src/layouts/payment-return/payment-return.vue diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 9b486517..f217dea4 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -1,5 +1,20 @@ const queryStrings = Object.freeze({ - ISS_PAGE: 'issPage' + ISS_PAGE: 'issPage', + ERROR: 'error', + SUBSCRIPTIONID: 'subscriptionid', + REFERRAL_SEQ_NUM: 'referralseqnum', + CARD_EXPIRATION_MONTH: 'card_expirationmonth', + CARD_EXPIRATION_YEAR: 'card_expirationyear', + CARD_TYPE: 'sgcardtype', + BILL_TO_POSTAL_CODE: 'billto_postalcode', + BILL_TO_FIRST_NAME: 'billto_firstname', + BILL_TO_LAST_NAME: 'billto_lastname', + REFERENCE_NUMBER: 'req_reference_number', + AUTH_CODE: 'auth_code', + TRANSACTION_ID: 'transaction_id', + TRANS_REFERENCE_NUMBER: 'auth_trans_ref_no', + LAST_FOUR: 'last_four', + DISPLAY_PAY_IN_ADVANCE_ALERT: 'displayPayInAdvanceAlert' }); export default queryStrings; diff --git a/src/constants/web-storage-constants.js b/src/constants/web-storage-constants.js new file mode 100644 index 00000000..29c814cf --- /dev/null +++ b/src/constants/web-storage-constants.js @@ -0,0 +1,5 @@ +const webStorageConstants = Object.freeze({ + SUBMITTED_ORDER: 'submittedOrder' +}); + +export default webStorageConstants; diff --git a/src/helpers/querystring-helper.js b/src/helpers/querystring-helper.js new file mode 100644 index 00000000..32900e96 --- /dev/null +++ b/src/helpers/querystring-helper.js @@ -0,0 +1,11 @@ +export default function getQuerystringParameter(key) { + const queryString = window.location.search; + const urlParams = new URLSearchParams(queryString); + const lowerCaseParams = new URLSearchParams(); + + urlParams.forEach((value, name) => { + lowerCaseParams.append(name.toLowerCase(), value); + }); + + return lowerCaseParams.get(key.toLowerCase()); +} diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index 7612e842..1f77de74 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -460,15 +460,11 @@ export default { computed: { payInAdvanceResponseUrl() { const { protocol, host } = window.location; - return `${protocol}//${host}/?issPage=${ - issPageValues.PAYMENT_RETURN - }&src=iss-nextgen`; + return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN}&src=iss-nextgen`; }, payInAdvanceCancelUrl() { const { protocol, host } = window.location; - return `${protocol}//${host}/?issPage=${ - issPageValues.PAYMENT_METHOD - }&src=iss-nextgen`; + return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_METHOD}&src=iss-nextgen`; }, dynamicCSSUrl() { const { protocol, hostname, port } = window.location; diff --git a/src/layouts/payment-return/payment-return.vue b/src/layouts/payment-return/payment-return.vue new file mode 100644 index 00000000..1ef57a4b --- /dev/null +++ b/src/layouts/payment-return/payment-return.vue @@ -0,0 +1,145 @@ + + + diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 1406498e..f50af7d5 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -91,6 +91,9 @@ const navigationScenarios = Object.freeze({ // Payment CLICKED_PAY_NOW: 'CLICKED_PAY_NOW', + PAY_IN_ADVANCE_ERROR: 'PAY_IN_ADVANCE_ERROR', + PAY_IN_ADVANCE_CREDIT_CARD_ERROR: 'PAY_IN_ADVANCE_CREDIT_CARD_ERROR', + PAY_IN_ADVANCE_SUCCESS: 'PAY_IN_ADVANCE_SUCCESS', // Bailout CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index df960f77..badf8d68 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -629,6 +629,23 @@ const routingTable = () => [ } ] }, + { + issPageValue: issPageValues.PAYMENT_RETURN, + maps: [ + { + scenario: navigationScenarios.PAY_IN_ADVANCE_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_METHOD + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_CREDIT_CARD_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_PAGE + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, + destinationIssPageValue: issPageValues.CONFIRMATION + }, + ] + }, { issPageValue: issPageValues.TPA_CONFIRMATION, maps: [ diff --git a/src/store/index.js b/src/store/index.js index 9dd4e7ce..8be154de 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -14,6 +14,7 @@ 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 webStorageConstants from '@/constants/web-storage-constants'; const storeId = 'main'; @@ -150,7 +151,21 @@ const getDefaultState = () => ({ }, parentAccountNumber: 0, isPayInAdvance: null, - payInAdvanceType: null + payInAdvanceType: null, + ccToken: { + subscriptionId: null, + expMonth: null, + expYear: null, + cardType: null, + billToPostalCode: null, + billToFirstName: null, + billToLastName: null, + referenceNumber: null, + authCode: null, + transactionId: null, + transReferenceNumber: null, + lastFour: null + } }, contactInfo: { firstName: null, @@ -175,8 +190,7 @@ const getDefaultState = () => ({ eon: null, workOrderNumber: null, originalDeductible: null, - currentDeductible: null, - carrierPhoneNumber: null + currentDeductible: null }, applicationUser: { experiments: [], @@ -926,18 +940,6 @@ export const useMainStore = defineStore({ }); }, - getCarrierAccountInfo() { - return new Promise((resolve, reject) => { - globalMethods.callHttpClient({ - method: endpoints.GetAccountInfo.method, - endpoint: endpoints.GetAccountInfo.url + this.issConfig.parentAccountNumber - }).then((response) => { - this.order.carrierPhoneNumber = response.data.phoneNumber; - return resolve(response.data); - }).catch((error) => reject(error)); - }); - }, - async getSupportingItems() { const glassPartsArray = this.order.lineItems.glassParts ?? []; const { carId } = this.order.vehicle; @@ -1397,6 +1399,10 @@ export const useMainStore = defineStore({ this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter; }, + resetState() { + Object.assign(this, getDefaultState()); + }, + resetRegistrationState() { this.order.vehicle.registration.licensePlate = null; this.order.vehicle.registration.address = null; @@ -2166,7 +2172,48 @@ export const useMainStore = defineStore({ method: endpoints.GetPaymentSignature.method, endpoint: endpoints.GetPaymentSignature.url }); - } + }, + + updateCCToken(ccToken) { + this.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; + this.order.payment.ccToken.expMonth = ccToken.expMonth; + this.order.payment.ccToken.expYear = ccToken.expYear; + this.order.payment.ccToken.cardType = ccToken.cardType; + this.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; + this.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; + this.order.payment.ccToken.billToLastName = ccToken.billToLastName; + this.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; + this.order.payment.ccToken.authCode = ccToken.authCode; + this.order.payment.ccToken.transactionId = ccToken.transactionId; + this.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; + this.order.payment.ccToken.lastFour = ccToken.lastFour; + }, + + hasSubmittedOrder() { + return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; + }, + + createSubmittedOrder() { + if (this.hasSubmittedOrder()) { + return; + } + const submittedOrder = this.order; + const { experiments } = this.applicationUser; + + // set to local storage + window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); + + // clear vuex + this.resetState(); + + // restore user's experiments + this.applicationUser.experiments = experiments; + }, + + resetSubmittedOrder() { + // clear from local storage + window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); + }, }, persist: true From 3dc288ae5cde4cd3df0cb0bb45408d1d2fef4d46 Mon Sep 17 00:00:00 2001 From: Josh Dassinger Date: Wed, 28 Feb 2024 08:00:11 -0600 Subject: [PATCH 564/674] SSR-512 PR Changes --- .../coverage-statement.spec.js | 49 ++++++++++--------- src/store/index.js | 7 +++ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index eef95eba..e4debdf7 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -824,6 +824,30 @@ describe.skip('coverageStatement.vue', () => { // Assert expect(wrapper.vm.mainStore.registerClaim).toHaveBeenCalled(); }); + }); +}); + +describe('coverageStatement.vue-working', () => { + describe('ITAC flag', () => { + test('ITAC flag updated once component is initialized', () => { + // Arrange + const mainInitialState = { + order: { + policy: { + isITAC: null + } + } + }; + const { wrapper } = getMountedComponent(mainInitialState); + + // Act + wrapper.vm.initializeComponent(); + + // Assert + expect(wrapper.vm.mainStore.updatePolicyITACFlag) + .toHaveBeenCalledTimes(1); + }); + it('Loaded duplicate with previously registered claim => claim registration is not called', async () => { // Arrange const sellingPrice = getRandomInt(50, 100); @@ -838,7 +862,7 @@ describe.skip('coverageStatement.vue', () => { } }, damage: { - isRepair: true + isRepair: false }, payment: { insuranceCoverage: { @@ -877,26 +901,3 @@ describe.skip('coverageStatement.vue', () => { }); }); }); - -describe('coverageStatement.vue-working', () => { - describe('ITAC flag', () => { - test('ITAC flag updated once component is initialized', () => { - // Arrange - const mainInitialState = { - order: { - policy: { - isITAC: null - } - } - }; - const { wrapper } = getMountedComponent(mainInitialState); - - // Act - wrapper.vm.initializeComponent(); - - // Assert - expect(wrapper.vm.mainStore.updatePolicyITACFlag) - .toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/src/store/index.js b/src/store/index.js index 85d5fb1a..f16f58e7 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1394,6 +1394,12 @@ export const useMainStore = defineStore({ }); }, + 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; }, @@ -2110,6 +2116,7 @@ export const useMainStore = defineStore({ this.order.loadedSessionClearedPreviousData = null; this.resetVehicleState(); this.resetDamageState(); + this.resetInsurance(); this.resetBailout(); }, From c7d7cbdf15cceea5f3b66657a0afcca5f34ad3ed Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Wed, 28 Feb 2024 10:26:30 -0500 Subject: [PATCH 565/674] refactor unit test --- .../order-confirmation/order-confirmation.spec.js | 12 +++++++++--- .../order-confirmation/order-confirmation.vue | 4 +--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index 79e4ea41..fe981266 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -29,6 +29,10 @@ const footerStub = { } }; +const headerStub = { + render: () => {} +}; + function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) { const mountOptions = getMountOptions({ router: { @@ -38,8 +42,10 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu }); mountOptions.global.stubs = { - siteFooter: footerStub + siteFooter: footerStub, + siteHeader: headerStub }; + const testingPinia = createTestingPinia({ initialState: { main: mainInitialState @@ -72,7 +78,7 @@ describe('OrderConfirmation.vue', () => { const { wrapper } = getMountedComponent({}); // Act - const siteHeader = wrapper.findComponent({ ref: 'siteHeader' }); + const siteHeader = wrapper.findComponent(headerStub); // Assert expect(siteHeader.exists()).toBe(true); @@ -121,5 +127,5 @@ describe('OrderConfirmation.vue', () => { // Assert expect(wrapper.vm.$router.navigateToExternalUrl).toHaveBeenCalledWith(carrierReturnUrl); }); - }) + }); }); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index cd06c4f1..57c8de44 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -6,9 +6,7 @@ @invalidSubmit="onInvalidSubmit">
    - +

    Placeholder for order confirmation page

    Date: Wed, 28 Feb 2024 11:19:15 -0500 Subject: [PATCH 566/674] Finalizing --- .../cart-dropdown/cart-dropdown.spec.js | 159 ++++++++++++++++++ .../cart-dropdown/cart-dropdown.vue | 66 ++++---- src/layouts/payment-method/payment-method.vue | 2 +- 3 files changed, 189 insertions(+), 38 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.spec.js b/src/iss-components/cart-dropdown/cart-dropdown.spec.js index e69de29b..e55bdc36 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.spec.js +++ b/src/iss-components/cart-dropdown/cart-dropdown.spec.js @@ -0,0 +1,159 @@ +import { shallowMount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue'; + +// Supporting Files +import { getMountOptions } from '@/helpers/unit-test-helper.js'; +import { useMainStore } from '@/store'; + +function getMountedComponent(mainInitialState = {}, initialData = {}, propsData = {}) { + const mountOptions = getMountOptions({ + router: { + navigate: jest.fn() + } + }); + + const testingPinia = createTestingPinia({ + initialState: { + main: mainInitialState + } + }); + useMainStore(testingPinia); + + mountOptions.global.plugins = [testingPinia]; + mountOptions.data = () => (initialData); + mountOptions.propsData = propsData; + + const wrapper = shallowMount(cartDropdown, mountOptions); + wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {}); + wrapper.vm.setCmsContent = jest.fn(); + return { wrapper }; +} + +describe('cart-dropdown component', () => { + test('initial data rendered as expected', () => { + // Arrange + const { wrapper } = getMountedComponent(); + + // Assert + expect(wrapper.vm.$data).toMatchSnapshot(); + }); + describe('displays', () => { + test('cart dropdown head', () => { + // Arrange + const reference = '#cart-dropdown-head'; + const { wrapper } = getMountedComponent(cartDropdown); + + // Act + const head = wrapper.find(reference); + + // Assert + expect(head.exists()).toBeTruthy(); + }); + test('cart table', () => { + // Arrange + const reference = '#cart-table'; + const isExpanded = true; + const initialData = { isExpanded }; + const { wrapper } = getMountedComponent(cartDropdown, {}, initialData); + + // Act + const cartTable = wrapper.find(reference); + + // Assert + expect(cartTable.exists()).toBeTruthy(); + }); + }); + describe('computed', () => { + test.each([ + [true, true], + [false, false], + [false, null] + ])('isVerified returns %p when isVerified store value is %p', (expected, isVerified) => { + // Arrange + const storeData = { + order: { + payment: { + insuranceCoverage: { isVerified } + } + } + }; + const { wrapper } = getMountedComponent(storeData); + + // Act + const result = wrapper.vm.isVerified; + + // Assert + expect(result).toBe(expected); + }); + describe('amountDueDisplayed', () => { + test('returns verifying coverage text when isVerified false', () => { + // Arrange + const VERIFYING_COVERAGE = 'Verifying coverage'; + const storeData = { + order: { + payment: { + insuranceCoverage: { + isVerified: false + } + } + } + }; + const { wrapper } = getMountedComponent(storeData); + + // Act + const result = wrapper.vm.amountDueDisplayed; + + // Assert + expect(result).toBe(VERIFYING_COVERAGE); + }); + test('returns formatted amount due when isVerified false', () => { + // TODO finish when methods done + }); + }); + describe('amountDue', () => { + test('returns 0 when showAsPaid is true', () => { + // Arrange + const propsData = { + showAsPaid: true + }; + const { wrapper } = getMountedComponent({}, {}, propsData); + + // Act + const result = wrapper.vm.amountDue; + + // Assert + expect(result).toBe(0); + }); + test('returns sum of subTotal and salesTax when showAsPaid is false', () => { + // TODO when subTotal and salesTax are finished + }); + }); + describe('subTotal', () => { + // TODO when method implemented + }); + describe('salesTax', () => { + // TODO when method implemented + }); + }); + describe('method', () => { + test.each([ + ['$0.00', 0], + ['$12.00', 12], + ['$12.30', 12.3], + ['$12.34', 12.34], + ['$12.35', 12.345], + ['$12.34', 12.344], + ['-$1.00', -1] + ])('get FormattedAmount returns `%` when amount %', (expected, amount) => { + // Arrange + const { wrapper } = getMountedComponent(); + + // Act + const result = wrapper.vm.getFormattedAmount(amount); + + // Assert + expect(result).toBe(expected); + }); + }); +}); diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index d2e2d641..a24f7b69 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -1,46 +1,39 @@ + diff --git a/src/layouts/tpa-confirmation/tpa-confirmation.vue b/src/layouts/tpa-confirmation/tpa-confirmation.vue index 135d47ab..2d777f8c 100644 --- a/src/layouts/tpa-confirmation/tpa-confirmation.vue +++ b/src/layouts/tpa-confirmation/tpa-confirmation.vue @@ -57,6 +57,7 @@ v-if="carrierUrl" ref="siteFooter" cmsWidgetName="SiteFooterWidget" + :isStackedVertically="true" :isForwardActionDisabled="!meta.valid" @ForwardClicked="forwardButtonAction" @backClicked="navigateBack" /> From 238879ea998e490ff64e25e8c395efe2a135dfad Mon Sep 17 00:00:00 2001 From: Josh Dassinger Date: Thu, 29 Feb 2024 09:01:26 -0600 Subject: [PATCH 570/674] SSR 512 - Skip policy vehicle page when loading session with policy vehicle --- src/helpers/policy-vehicle-helper.js | 23 ++ src/helpers/policy-vehicle-helper.spec.js | 205 ++++++++++++++++++ .../coverage-statement.spec.js | 7 +- .../policy-vehicles/policy-vehicles.spec.js | 178 ++++++++------- .../policy-vehicles/policy-vehicles.vue | 35 ++- src/router/router-constants/routing-table.js | 2 +- src/store/index.js | 130 ++++++----- 7 files changed, 416 insertions(+), 164 deletions(-) create mode 100644 src/helpers/policy-vehicle-helper.js create mode 100644 src/helpers/policy-vehicle-helper.spec.js diff --git a/src/helpers/policy-vehicle-helper.js b/src/helpers/policy-vehicle-helper.js new file mode 100644 index 00000000..69a80e74 --- /dev/null +++ b/src/helpers/policy-vehicle-helper.js @@ -0,0 +1,23 @@ +import endorsementOptions from '@/constants/endorsement-options'; + +export function noCoverageForSelectedVehicle(vehicle) { + return (vehicle?.coverages?.length ?? 0) === 0; +} +export function deductibleForSelectedVehicle(vehicle) { + if (!vehicle) { + return undefined; + } + + return vehicle.coverages?.length ?? false + ? vehicle?.coverages[0].deductible + : 0; +} +export function endorsementsForSelectedVehicle(vehicle) { + if (vehicle?.endorsements?.length > 0) { + return vehicle.endorsements; + } + return []; +} +export function repairWaivedForSelectedVehicle(vehicle) { + return vehicle?.endorsements?.includes(endorsementOptions.REPAIR_WAIVED) ?? false; +} diff --git a/src/helpers/policy-vehicle-helper.spec.js b/src/helpers/policy-vehicle-helper.spec.js new file mode 100644 index 00000000..be3411b3 --- /dev/null +++ b/src/helpers/policy-vehicle-helper.spec.js @@ -0,0 +1,205 @@ +import { + deductibleForSelectedVehicle, + endorsementsForSelectedVehicle, + noCoverageForSelectedVehicle, + repairWaivedForSelectedVehicle +} from '@/helpers/policy-vehicle-helper'; +import { getRandomInt, getRandomString } from '@/helpers/data-generation'; +import endorsementOptions from '@/constants/endorsement-options'; + +describe('policy vehicle helper', () => { + describe('noCoverageForSelectedVehicle function', () => { + it('Null vehicle => returns true', async () => { + // Arrange + const vehicle = null; + + // Act + const result = noCoverageForSelectedVehicle(vehicle); + + // Assert + expect(result).toBeTruthy(); + }); + + it('Empty vehicle coverages list => returns true', async () => { + // Arrange + const vehicle = { + vin: getRandomString(17, 17), + coverages: [] + }; + + // Act + const result = noCoverageForSelectedVehicle(vehicle); + + // Assert + expect(result).toBeTruthy(); + }); + + it('Non-empty vehicle coverages list => returns false', async () => { + // Arrange + const vehicle = { + vin: getRandomString(17, 17), + coverages: [ + { + deductible: 0 + } + ] + }; + + // Act + const result = deductibleForSelectedVehicle(vehicle); + + // Assert + expect(result).toBeFalsy(); + }); + }); + + describe('deductibleForSelectedVehicle function', () => { + it('Null vehicle => returns undefined', async () => { + // Arrange + const vehicle = null; + + // Act + const result = deductibleForSelectedVehicle(vehicle); + + // Assert + expect(result).toBe(undefined); + }); + + it('Vehicle match with empty coverages list => 0 returned', async () => { + // Arrange + const vehicle = { + vin: getRandomString(17, 17), + coverages: [] + }; + + // Act + const result = deductibleForSelectedVehicle(vehicle); + + // Assert + expect(result).toBe(0); + }); + + it('Coverages list non empty => deductible from first coverage returned', async () => { + // Arrange + const firstDeductible = getRandomInt(1, 1000); + const vehicle = { + vin: getRandomString(17, 17), + coverages: [ + { + deductible: firstDeductible + }, + { + deductible: getRandomInt(1, 1000) + } + ] + }; + + // Act + const result = deductibleForSelectedVehicle(vehicle); + + // Assert + expect(result).toBe(firstDeductible); + }); + }); + + describe('repairWaivedForSelectedVehicle function', () => { + it('Null vehicle => returns false', async () => { + // Arrange + const vehicle = null; + + // Act + const result = repairWaivedForSelectedVehicle(vehicle); + + // Assert + expect(result).toBeFalsy(); + }); + + it('Endorsements list empty => false returned', async () => { + // Arrange + const vehicle = { + vin: getRandomString(17, 17), + endorsements: [] + }; + + // Act + const result = repairWaivedForSelectedVehicle(vehicle); + + // Assert + expect(result).toBeFalsy(); + }); + + it('Endorsements list non-empty, not containing repair waived => false returned', async () => { + // Arrange + const vehicle = { + vin: getRandomString(17, 17), + endorsements: [endorsementOptions.EDUCATOR, endorsementOptions.PARKING_GUARD] + }; + + // Act + const result = repairWaivedForSelectedVehicle(vehicle); + + // Assert + expect(result).toBeFalsy(); + }); + + it('Endorsements list contains repair waived => true returned', async () => { + // Arrange + const vehicle = { + vin: getRandomString(17, 17), + endorsements: [ + endorsementOptions.EDUCATOR, + endorsementOptions.REPAIR_WAIVED, + endorsementOptions.PARKING_GUARD + ] + }; + + // Act + const result = repairWaivedForSelectedVehicle(vehicle); + + // Assert + expect(result).toBeTruthy(); + }); + }); + + describe('endorsementsForSelectedVehicle function', () => { + it('Null vehicle => returns empty array', async () => { + // Arrange + const vehicle = null; + + // Act + const result = endorsementsForSelectedVehicle(vehicle); + + // Assert + expect(result).toStrictEqual([]); + }); + + it('Null endorsements => returns empty array', async () => { + // Arrange + const vehicle = { + vin: getRandomString(17, 17), + endorsements: null + }; + + // Act + const result = endorsementsForSelectedVehicle(vehicle); + + // Assert + expect(result).toStrictEqual([]); + }); + + it('Endorsements list non-empty, not containing repair waived => false returned', async () => { + // Arrange + const endorsements = [endorsementOptions.EDUCATOR, endorsementOptions.PARKING_GUARD]; + const vehicle = { + vin: getRandomString(17, 17), + endorsements + }; + + // Act + const result = endorsementsForSelectedVehicle(vehicle); + + // Assert + expect(result).toStrictEqual(endorsements); + }); + }); +}); diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index e4debdf7..a597b7f9 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -829,7 +829,7 @@ describe.skip('coverageStatement.vue', () => { describe('coverageStatement.vue-working', () => { describe('ITAC flag', () => { - test('ITAC flag updated once component is initialized', () => { + test('ITAC flag updated once component is initialized', async () => { // Arrange const mainInitialState = { order: { @@ -838,7 +838,10 @@ describe('coverageStatement.vue-working', () => { } } }; - const { wrapper } = getMountedComponent(mainInitialState); + const mockStoreActions = () => { + useMainStore().getPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve([])); + }; + const { wrapper } = getMountedComponent(mainInitialState, {}, mockStoreActions); // Act wrapper.vm.initializeComponent(); diff --git a/src/layouts/policy-vehicles/policy-vehicles.spec.js b/src/layouts/policy-vehicles/policy-vehicles.spec.js index 1c88dd4b..9168feb0 100644 --- a/src/layouts/policy-vehicles/policy-vehicles.spec.js +++ b/src/layouts/policy-vehicles/policy-vehicles.spec.js @@ -102,10 +102,12 @@ describe('policy-vehicles.vue', () => { const { wrapper } = setupMocks({}); const vin = getRandomString(17, 17); + const policyVehicle = { vin }; await wrapper.setData({ selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { vin } + policyVehicle ], policyVinFound: true }); @@ -202,13 +204,15 @@ describe('policy-vehicles.vue', () => { const vin = getRandomString(17, 17); const endorsements = ['Parking Guard']; + const policyVehicle = { + vin, + endorsements + }; await wrapper.setData({ selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - endorsements - } + policyVehicle ] }); @@ -342,12 +346,14 @@ describe('policy-vehicles.vue', () => { // Arrange const selectedVin = getRandomString(17, 17); const otherVin = getRandomString(17, 17); + const policyVehicle = { + vin: otherVin + }; const testValues = { selectedVehicleVin: selectedVin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin: otherVin - } + policyVehicle ] }; @@ -361,13 +367,15 @@ describe('policy-vehicles.vue', () => { it('Coverages list empty => true', () => { // Arrange const vin = getRandomString(17, 17); + const policyVehicle = { + vin, + coverages: [] + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - coverages: [] - } + policyVehicle ] }; @@ -381,17 +389,19 @@ describe('policy-vehicles.vue', () => { it('Coverages list non-empty => false', () => { // Arrange const vin = getRandomString(17, 17); + const policyVehicle = { + vin, + coverages: [ + { + deductible: 0 + } + ] + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - coverages: [ - { - deductible: 0 - } - ] - } + policyVehicle ] }; @@ -410,6 +420,7 @@ describe('policy-vehicles.vue', () => { const otherVin = getRandomString(17, 17); const testValues = { selectedVehicleVin: selectedVin, + selectedPolicyVehicle: null, policyVehicles: [ { vin: otherVin @@ -427,13 +438,15 @@ describe('policy-vehicles.vue', () => { it('Vehicle match with empty coverages list => 0 returned', () => { // Arrange const vin = getRandomString(17, 17); + const policyVehicle = { + vin, + coverages: [] + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - coverages: [] - } + policyVehicle ] }; @@ -449,20 +462,22 @@ describe('policy-vehicles.vue', () => { const vin = getRandomString(17, 17); const firstDeductible = getRandomInt(1, 1000); const secondDeductible = getRandomInt(1, 1000); + const policyVehicle = { + vin, + coverages: [ + { + deductible: firstDeductible + }, + { + deductible: secondDeductible + } + ] + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - coverages: [ - { - deductible: firstDeductible - }, - { - deductible: secondDeductible - } - ] - } + policyVehicle ] }; @@ -481,6 +496,7 @@ describe('policy-vehicles.vue', () => { const otherVin = getRandomString(17, 17); const testValues = { selectedVehicleVin: selectedVin, + selectedPolicyVehicle: null, policyVehicles: [ { vin: otherVin @@ -498,13 +514,15 @@ describe('policy-vehicles.vue', () => { it('Endorsements list empty => false returned', () => { // Arrange const vin = getRandomString(17, 17); + const policyVehicle = { + vin, + endorsements: [] + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - endorsements: [] - } + policyVehicle ] }; @@ -518,13 +536,15 @@ describe('policy-vehicles.vue', () => { it('Endorsements list non-empty, not containing repair waived => false returned', () => { // Arrange const vin = getRandomString(17, 17); + const policyVehicle = { + vin, + endorsements: [endorsementOptions.EDUCATOR, endorsementOptions.PARKING_GUARD] + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - endorsements: [endorsementOptions.EDUCATOR, endorsementOptions.PARKING_GUARD] - } + policyVehicle ] }; @@ -538,17 +558,19 @@ describe('policy-vehicles.vue', () => { it('Endorsements list contains repair waived => true returned', () => { // Arrange const vin = getRandomString(17, 17); + const policyVehicle = { + vin, + endorsements: [ + endorsementOptions.EDUCATOR, + endorsementOptions.REPAIR_WAIVED, + endorsementOptions.PARKING_GUARD + ] + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - endorsements: [ - endorsementOptions.EDUCATOR, - endorsementOptions.REPAIR_WAIVED, - endorsementOptions.PARKING_GUARD - ] - } + policyVehicle ] }; @@ -564,6 +586,7 @@ describe('policy-vehicles.vue', () => { it('policyVehicles is null => empty endorsements array returned', () => { // Arrange const testValues = { + selectedPolicyVehicle: null, policyVehicles: null }; @@ -578,6 +601,7 @@ describe('policy-vehicles.vue', () => { it('policyVehicles is empty => empty endorsements array returned', () => { // Arrange const testValues = { + selectedPolicyVehicle: null, policyVehicles: [] }; @@ -595,6 +619,7 @@ describe('policy-vehicles.vue', () => { const otherVin = getRandomString(17, 17); const testValues = { selectedVehicleVin: selectedVin, + selectedPolicyVehicle: null, policyVehicles: [ { vin: otherVin @@ -613,13 +638,15 @@ describe('policy-vehicles.vue', () => { it('vehicle VIN match with endorsements null => empty endorsements array returned', () => { // Arrange const vin = getRandomString(17, 17); + const policyVehicle = { + vin, + endorsements: null + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - endorsements: null - } + policyVehicle ] }; @@ -634,13 +661,15 @@ describe('policy-vehicles.vue', () => { it('vehicle VIN match with empty endorsements => empty endorsements array returned', () => { // Arrange const vin = getRandomString(17, 17); + const policyVehicle = { + vin, + endorsements: [] + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - endorsements: [] - } + policyVehicle ] }; @@ -656,13 +685,15 @@ describe('policy-vehicles.vue', () => { // Arrange const vin = getRandomString(17, 17); const endorsements = [getRandomString(10, 20)]; + const policyVehicle = { + vin, + endorsements + }; const testValues = { selectedVehicleVin: vin, + selectedPolicyVehicle: policyVehicle, policyVehicles: [ - { - vin, - endorsements - } + policyVehicle ] }; @@ -694,25 +725,4 @@ describe('policy-vehicles.vue', () => { // Assert expect(wrapper.vm.selectedVehicleVin).toBe(vin); }); - - test('load session vehicle is auto-selected if vehicle is on policy', async () => { - // Arrange - const vin = getRandomString(17, 17); - useMainStore().order = { - policy: { - vehicles: [{ vin }] - }, - vehicle: { - vin - } - }; - - const { wrapper } = setupMocks(); - - // Act - await wrapper.vm.$nextTick(); - - // Assert - expect(wrapper.vm.selectedVehicleVin).toBe(vin); - }); }); diff --git a/src/layouts/policy-vehicles/policy-vehicles.vue b/src/layouts/policy-vehicles/policy-vehicles.vue index c553066c..915b97e8 100644 --- a/src/layouts/policy-vehicles/policy-vehicles.vue +++ b/src/layouts/policy-vehicles/policy-vehicles.vue @@ -53,8 +53,12 @@ import vehicleSelectionOptions from '@/constants/vehicle-selection-options.js'; import endorsementOptions from '@/constants/endorsement-options.js'; import globalRules from '@/constants/global-rules.js'; import { useMainStore } from '@/store/index.js'; -import bailoutCode from '@/constants/bailoutCode'; import bailoutMessage from '@/constants/bailoutMessage'; +import { + deductibleForSelectedVehicle, endorsementsForSelectedVehicle, + noCoverageForSelectedVehicle, + repairWaivedForSelectedVehicle +} from '@/helpers/policy-vehicle-helper'; export default { name: 'policy-vehicles', @@ -82,6 +86,7 @@ export default { return { policyVehicles, selectedVehicleVin: '', + selectedPolicyVehicle: null, displayGeneric: true, policyVinFound: true, rules: { @@ -108,33 +113,16 @@ export default { return mappedData; }, noCoverageForSelectedVehicle() { - const vehicle = this.policyVehicles?.find((policyVehicle) => - policyVehicle.vin === this.selectedVehicleVin); - return (vehicle?.coverages?.length ?? 0) === 0; + return noCoverageForSelectedVehicle(this.selectedPolicyVehicle); }, deductibleForSelectedVehicle() { - const vehicle = this.policyVehicles?.find((policyVehicle) => - policyVehicle?.vin === this.selectedVehicleVin); - if (!vehicle) { - return undefined; - } - - return vehicle.coverages?.length ?? false - ? vehicle?.coverages[0].deductible - : 0; + return deductibleForSelectedVehicle(this.selectedPolicyVehicle); }, endorsementsForSelectedVehicle() { - const vehicle = this.policyVehicles?.find((policyVehicle) => - policyVehicle?.vin === this.selectedVehicleVin); - if (vehicle?.endorsements?.length > 0) { - return vehicle.endorsements; - } - return []; + return endorsementsForSelectedVehicle(this.selectedPolicyVehicle); }, repairWaivedForSelectedVehicle() { - const vehicle = this.policyVehicles?.find((policyVehicle) => - policyVehicle.vin === this.selectedVehicleVin); - return vehicle?.endorsements?.includes(endorsementOptions.REPAIR_WAIVED) ?? false; + return repairWaivedForSelectedVehicle(this.selectedPolicyVehicle); }, selectedVehicle() { const vehicle = this.mainStore.lookupVehicleByVin(this.selectedVehicleVin); @@ -147,6 +135,7 @@ export default { // clear previously selected vehicle and image this.mainStore.resetVehicleState(); this.displayGeneric = true; + this.selectedPolicyVehicle = null; } else { // get vehicle details from selected VIN const vehicle = await this.lookupVehicleByVin(value); @@ -155,12 +144,14 @@ export default { if (vehicle?.error === true) { this.mainStore.resetVehicleState(); this.displayGeneric = true; + this.selectedPolicyVehicle = null; return; } if (vehicle) { // save selected vehicle to the store this.mainStore.updateVehicle(vehicle.data); this.displayGeneric = false; + this.selectedPolicyVehicle = this.policyVehicles.find((p) => p.vin === value); } } } diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 9e876ea5..d20f59cd 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -423,7 +423,7 @@ const routingTable = () => [ }, { scenario: navigationScenarios.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_POLICY_VEHICLE, - destinationIssPageValue: issPageValues.POLICY_VEHICLES + destinationIssPageValue: issPageValues.VEHICLE_DAMAGE }, { scenario: navigationScenarios.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NON_POLICY_VEHICLE, diff --git a/src/store/index.js b/src/store/index.js index f16f58e7..1b969be8 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -14,6 +14,11 @@ 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'; @@ -1192,11 +1197,12 @@ export const useMainStore = defineStore({ }); }, - loadSession() { + async loadSession() { const { applicationUser, order, issConfig } = this; // TODO how to get savedSessionId for a duplicate referral? - return new Promise((resolve, reject) => { - globalMethods.callHttpClient({ + + try { + const response = await globalMethods.callHttpClient({ method: endpoints.LoadSession.method, endpoint: endpoints.LoadSession.url, payload: { @@ -1206,67 +1212,81 @@ export const useMainStore = defineStore({ parentAccountNumber: issConfig.parentAccountNumber, referralCorrelationId: order.referralCorrelationId } - }).then((response) => { - const { data } = response; - if (!data) { - // TODO how should we handle this case? - return resolve(data); - } + }); + 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; + 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; + 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.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.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; + 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) { - order.vehicle.vin = data.vehicle.vin; + 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 resolve(data); - }, (error) => { - reject(error); - }); - }); + 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) { @@ -1425,7 +1445,7 @@ export const useMainStore = defineStore({ // These could be undefined this.order.policy.noCoverage = vehicle.noCoverage; - if (this.order.payment.insuranceCoverage.coverageStatus === coverageStatuses.PENDING) { + if (!this.order.payment.insuranceCoverage.claimNumber) { this.order.payment.insuranceCoverage.coverageStatus = vehicle.noCoverage ? coverageStatuses.NO_COMP : coverageStatuses.PENDING; From 066017d5fddccde3fe17e64dcae94c92bc38e87c Mon Sep 17 00:00:00 2001 From: Josh Dassinger Date: Thu, 29 Feb 2024 09:15:29 -0600 Subject: [PATCH 571/674] SSR-512 Fix misspelled field --- src/store/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 8e628b98..0609256d 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1229,7 +1229,7 @@ export const useMainStore = defineStore({ const { data } = response; if (!data) { // TODO how should we handle this case? - return respone; + return response; } applicationUser.crmCustomerId = data.applicationUser?.crmCustomerId; From a8b75d8c1cc7684cab31697a29f2c6061c9b9c6a Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 29 Feb 2024 14:39:35 -0500 Subject: [PATCH 572/674] Adding deductible and base price line items to cart --- .../cart-dropdown/cart-dropdown.spec.js | 2 +- .../cart-dropdown/cart-dropdown.vue | 95 +++++++++++++++---- .../coverage-statement/coverage-statement.vue | 8 +- src/layouts/payment-method/payment-method.vue | 26 ++++- src/store/index.js | 23 ++--- 5 files changed, 116 insertions(+), 38 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.spec.js b/src/iss-components/cart-dropdown/cart-dropdown.spec.js index e55bdc36..b2fc6245 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.spec.js +++ b/src/iss-components/cart-dropdown/cart-dropdown.spec.js @@ -81,7 +81,7 @@ describe('cart-dropdown component', () => { const { wrapper } = getMountedComponent(storeData); // Act - const result = wrapper.vm.isVerified; + const result = wrapper.vm.isVerifiedCoverageStatus; // Assert expect(result).toBe(expected); diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 9ebfa58d..2dd9210c 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -10,13 +10,34 @@ href="javascript:void(0)" class="col d-flex justify-content-between py-0"> {{ amountDueLabel }} - {{ amountDueDisplayed }} + {{ getDisplayed(amountDue) }}
    - Cart Table Placeholder + class="cart-table"> +
    +
    +
    + {{ deductibleOrBasePriceLabel }} + {{ getDisplayed(deductible) }} +
    +
    + {{ deductibleOrBasePriceLabel }} + {{ getDisplayed(baseServicePrice) }} +
    +
    +
    @@ -31,39 +52,56 @@ export default { components: {}, props: { showAsPaid: Boolean, - amountDueLabel: String + amountDueLabel: String, + deductibleOrBasePriceLabel: String }, data() { return { - isExpanded: false, + isExpanded: true, currencyFormatter: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' - }), - widget: { - amountDue: 'AmountDueTextWidget' - } + }) }; }, computed: { - isVerified() { - return useMainStore().payment?.insuranceCoverage?.isVerified ?? false; + deductible() { + return useMainStore().order.currentDeductible; }, - amountDueDisplayed() { - return this.isVerified - ? this.getFormattedAmount(this.amountDue) - : VERIFYING_COVERAGE; + availableLineItems() { + // TODO make real + return [ + { + kitPrice: 1, + laborAmount: 2, + sellingPrice: 3 + } + ]; + }, + baseServicePrice() { + return this.availableLineItems + .reduce( + (accumulator, lineItem) => accumulator + this.getTotalLineItemPrice(lineItem), + 0 + ); + }, + showDeductibleLineItem() { + return !useMainStore().isNoComp && !useMainStore().policy.isITAC; + }, + isUnverified() { + return this.showDeductibleLineItem + && (this.deductible == null || !useMainStore().isVerifiedCoverageStatus); + }, + subTotal() { + return this.showDeductibleLineItem ? this.deductible : this.baseServicePrice; + }, + salesTax() { + return 0; // TODO }, amountDue() { return this.showAsPaid ? 0 : this.subTotal + this.salesTax; - }, - subTotal() { - return 0; - }, - salesTax() { - return 0; } }, methods: { @@ -72,6 +110,14 @@ export default { }, getFormattedAmount(amount) { return this.currencyFormatter.format(amount); + }, + getTotalLineItemPrice(lineItem) { + return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; + }, + getDisplayed(amount) { + return this.isUnverified + ? VERIFYING_COVERAGE + : this.getFormattedAmount(amount); } } }; @@ -84,6 +130,13 @@ export default { .color-black { color: $black; } +.color-gray-100 { + background-color: $gray-100; +} + +.line-item { + color: $darker-gray; +} .cart-table { max-height: 0; diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index fa6f17c3..bcdc76cb 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -130,6 +130,7 @@ import routerParams from '@/router/router-constants/router-params'; import issPageValues from '@/router/router-constants/issPage-values'; import bailoutCode from '@/constants/bailoutCode'; import bailoutMessage from '@/constants/bailoutMessage'; +import coverageStatuses from '@/constants/coverage-statuses'; export default { name: 'coverage-statement', @@ -265,8 +266,7 @@ export default { return damageString === 'match' ? '' : damageString; }, vehicleDeductible() { - const deductible = useMainStore().order.currentDeductible; - return deductible; + return useMainStore().order.currentDeductible; }, formattedDeductible() { return this.getDeductibleString(this.vehicleDeductible); @@ -355,6 +355,10 @@ export default { }, async initializeComponent() { useMainStore().updatePolicyITACFlag(this.verifiedITAC); + const coverageStatus = this.verifiedITAC || this.verifiedNoComp + ? coverageStatuses.VERIFIED + : coverageStatuses.PENDING; + useMainStore().updateCoverageStatus(coverageStatus); if (this.policyLookupSuccessful && useMainStore().order.vehicle.policyVehicleId >= 0 && useMainStore().isClaimRegistrationRequired diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 8b03a875..1cafe4ef 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -21,7 +21,8 @@
    + :amountDueLabel="amountDueText" + :deductibleOrBasePriceLabel="deductibleOrBasePriceLabel" />
    Pia Alert Placeholder
    state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF, isClaimRegistrationRequired: (state) => state.issConfig.isClaimRegistrationRequired, isBailout: (state) => state.applicationUser.pageData[issPageValues.BAILOUT_PAGE] != null, + isNoComp: (state) => state.order.policy.coverageStatus === coverageStatuses.NO_COMP, + isVerifiedCoverageStatus: (state) => state.order.policy.coverageStatus === coverageStatuses.VERIFIED, eventBusItem: (state) => (eventCategory, eventSubCategory) => { const matchedEvent = state.applicationUser.eventBus.find(({ category, subCategory }) => category === eventCategory && subCategory === eventSubCategory); return matchedEvent?.eventValue; @@ -489,6 +491,9 @@ export const useMainStore = defineStore({ }); }); }, + updateCoverageStatus(newStatus) { + this.order.payment.insuranceCoverage.coverageStatus = newStatus; + }, registerClaim() { const nonNumberCharRegex = /[^0-9]/g; const { order } = this; @@ -553,18 +558,15 @@ export const useMainStore = defineStore({ 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; + if (this.policy?.noCoverage ?? false) { + this.updateCoverageStatus(coverageStatuses.NO_COMP); + } else if (!registerClaimFailed) { + this.updateCoverageStatus(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); }); @@ -1264,7 +1266,7 @@ export const useMainStore = defineStore({ order.lineItems.vaps = data.order?.lineItems?.vaps; order.payment.insuranceCoverage.isVerified = data.order?.payment?.insuranceCoverage?.isVerified; - order.payment.insuranceCoverage.coverageStatus = data.order?.payment?.insuranceCoverage?.coverageStatus; + this.updateCoverageStatus(data.order?.payment?.insuranceCoverage?.coverageStatus ?? coverageStatuses.PENDING); const parentAccountNumber = Number.isNaN(data.order?.payment?.parentAccountNumber) ? 0 : data.order?.payment?.parentAccountNumber; @@ -1466,9 +1468,8 @@ export const useMainStore = defineStore({ // These could be undefined this.order.policy.noCoverage = vehicle.noCoverage; - this.order.payment.insuranceCoverage.coverageStatus = vehicle.noCoverage - ? coverageStatuses.NO_COMP - : coverageStatuses.PENDING; + const currentCoverageStatus = vehicle.noCoverage ? coverageStatuses.NO_COMP : coverageStatuses.PENDING; + this.updateCoverageStatus(currentCoverageStatus); this.order.policy.deductible.replace = vehicle.deductible; this.order.policy.deductible.repair = vehicle?.repairWaived ?? false ? 0 : vehicle.deductible; this.order.policy.endorsements = vehicle?.endorsements; From b5e24c814688664da74ae7aea9b6dea7e93b0725 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 29 Feb 2024 14:49:53 -0500 Subject: [PATCH 573/674] Separating deductible and base pay --- .../cart-dropdown/cart-dropdown.vue | 7 ++-- src/layouts/payment-method/payment-method.vue | 32 ++++++++----------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 2dd9210c..1d52f580 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -24,7 +24,7 @@ class="d-flex justify-content-between align-items-center"> {{ deductibleOrBasePriceLabel }} + class="label">{{ deductibleLabel }} {{ getDisplayed(deductible) }}
    {{ deductibleOrBasePriceLabel }} + class="label">{{ BasePriceLabel }} {{ getDisplayed(baseServicePrice) }}
    @@ -53,7 +53,8 @@ export default { props: { showAsPaid: Boolean, amountDueLabel: String, - deductibleOrBasePriceLabel: String + deductibleLabel: String, + basePriceLabel: String }, data() { return { diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 1cafe4ef..a57577f1 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -22,7 +22,8 @@ + :deductibleLabel="deductibleLabel" + :basePriceLabel="basePriceLabel" />
    Pia Alert Placeholder
    Date: Thu, 29 Feb 2024 14:53:54 -0500 Subject: [PATCH 574/674] Cleaning 1 --- .../cart-dropdown/cart-dropdown.vue | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 1d52f580..579162c9 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -16,26 +16,26 @@
    -
    -
    -
    - {{ deductibleLabel }} - {{ getDisplayed(deductible) }} -
    -
    - {{ BasePriceLabel }} - {{ getDisplayed(baseServicePrice) }} -
    +
    +
    + {{ deductibleLabel }} + {{ getDisplayed(deductible) }} +
    +
    + {{ BasePriceLabel }} + {{ getDisplayed(baseServicePrice) }}
    From 5f6b99b0f1f838a8bd744b99ec2b86e06fcb8150 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 29 Feb 2024 14:56:00 -0500 Subject: [PATCH 575/674] Making base service price never say unverified --- src/iss-components/cart-dropdown/cart-dropdown.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 579162c9..e9d0da00 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -10,7 +10,7 @@ href="javascript:void(0)" class="col d-flex justify-content-between py-0"> {{ amountDueLabel }} - {{ getDisplayed(amountDue) }} + {{ getDisplayedByUnverified(amountDue) }}
    {{ deductibleLabel }} - {{ getDisplayed(deductible) }} + {{ getDisplayedByUnverified(deductible) }}
    {{ BasePriceLabel }} - {{ getDisplayed(baseServicePrice) }} + {{ getFormattedAmount(baseServicePrice) }}
    @@ -115,7 +115,7 @@ export default { getTotalLineItemPrice(lineItem) { return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; }, - getDisplayed(amount) { + getDisplayedByUnverified(amount) { return this.isUnverified ? VERIFYING_COVERAGE : this.getFormattedAmount(amount); From e40a7eef23935d34be0847aa1492a4c60dd39e77 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 29 Feb 2024 14:58:01 -0500 Subject: [PATCH 576/674] Removing debug bool --- src/iss-components/cart-dropdown/cart-dropdown.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index e9d0da00..546ca470 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -58,7 +58,7 @@ export default { }, data() { return { - isExpanded: true, + isExpanded: false, currencyFormatter: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' From 9e346265cc7f2586b0dfcddc159311198fcd7b19 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 29 Feb 2024 15:02:34 -0500 Subject: [PATCH 577/674] Simplifying --- src/iss-components/cart-dropdown/cart-dropdown.vue | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 546ca470..e9b23408 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -10,7 +10,7 @@ href="javascript:void(0)" class="col d-flex justify-content-between py-0"> {{ amountDueLabel }} - {{ getDisplayedByUnverified(amountDue) }} + {{ getDisplayed(amountDue) }}
    {{ deductibleLabel }} - {{ getDisplayedByUnverified(deductible) }} + {{ getDisplayed(deductible) }}
    {{ BasePriceLabel }} - {{ getFormattedAmount(baseServicePrice) }} + {{ getDisplayed(baseServicePrice) }}
    @@ -79,6 +79,7 @@ export default { } ]; }, + // TODO share with claim registration page baseServicePrice() { return this.availableLineItems .reduce( @@ -94,6 +95,7 @@ export default { && (this.deductible == null || !useMainStore().isVerifiedCoverageStatus); }, subTotal() { + // TODO partial calculation for now return this.showDeductibleLineItem ? this.deductible : this.baseServicePrice; }, salesTax() { @@ -112,11 +114,12 @@ export default { getFormattedAmount(amount) { return this.currencyFormatter.format(amount); }, + // TODO share with claim registration page getTotalLineItemPrice(lineItem) { return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; }, - getDisplayedByUnverified(amount) { - return this.isUnverified + getDisplayed(amount) { + return this.isUnverified && this.showDeductibleLineItem ? VERIFYING_COVERAGE : this.getFormattedAmount(amount); } From 7e9f7d83c017e64c060b93c4d7aa0014b0b6ec75 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Thu, 29 Feb 2024 15:06:39 -0500 Subject: [PATCH 578/674] Simplifying 2 --- src/layouts/payment-method/payment-method.vue | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index a57577f1..efdbb703 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -140,16 +140,10 @@ export default { return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT); }, deductibleLabel() { - return this.getCmsContent( - this.widget.deductible, - widgetFields.TEXT_BLOCK_WIDGET.TEXT - ); + return this.getCmsContent(this.widget.deductible, widgetFields.TEXT_BLOCK_WIDGET.TEXT); }, basePriceLabel() { - return this.getCmsContent( - this.widget.basePrice, - widgetFields.TEXT_BLOCK_WIDGET.TEXT - ); + return this.getCmsContent(this.widget.basePrice, widgetFields.TEXT_BLOCK_WIDGET.TEXT); } }, watch: { From effb1816990bc52ada01b9c7f4da3777fecc9060 Mon Sep 17 00:00:00 2001 From: Josh Dassinger Date: Thu, 29 Feb 2024 14:22:11 -0600 Subject: [PATCH 579/674] SSR-512 Change back to pending status for load session coverage --- src/store/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 0609256d..114b9989 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1458,7 +1458,7 @@ export const useMainStore = defineStore({ // These could be undefined this.order.policy.noCoverage = vehicle.noCoverage; - if (!this.order.payment.insuranceCoverage.claimNumber) { + if (this.order.payment.insuranceCoverage.coverageStatus === coverageStatuses.PENDING) { this.order.payment.insuranceCoverage.coverageStatus = vehicle.noCoverage ? coverageStatuses.NO_COMP : coverageStatuses.PENDING; From a97cc337b165f4e5449ada6cbea1f99c6af9039d Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Thu, 29 Feb 2024 15:42:15 -0500 Subject: [PATCH 580/674] add appointment details to order-confirmation page --- src/helpers/date-helper.js | 32 +++ .../order-confirmation.spec.js | 215 +++++++++++++++++- .../order-confirmation/order-confirmation.vue | 165 +++++++++++++- 3 files changed, 402 insertions(+), 10 deletions(-) diff --git a/src/helpers/date-helper.js b/src/helpers/date-helper.js index 1b062c85..be8161e8 100644 --- a/src/helpers/date-helper.js +++ b/src/helpers/date-helper.js @@ -72,3 +72,35 @@ export function sumDateString(dateString, daysToAdd) { date.setDate(date.getDate() + daysToAdd); return convertDateToDateString(date); } + +export function get12HourTimeMobileFormat(time) { + // Check correct time format and split into components + let timeString = time.toString().match(/^([01]\d|2[0-3])(:)([0-5]\d)?$/) || [time]; + + if (timeString.length > 1) { + // If time format correct + const min = timeString[3]; + timeString = timeString.slice(1); // Remove full string match value + if (Number(min) === 0) { + timeString = timeString.slice(0, 1); // Remove minute value + timeString[1] = +timeString[0] < 12 ? ' AM' : ' PM'; // Set AM/PM + } else { + timeString[5] = +timeString[0] < 12 ? ' AM' : ' PM'; // Set AM/PM + } + timeString[0] = +timeString[0] % 12 || 12; // Adjust hours + } + return timeString.join(''); // return adjusted time or original string +} + +export function get12HourTimeFormat(time) { + // Check correct time format and split into components + let timeString = time.toString().match(/^([01]\d|2[0-3])(:)([0-5]\d)?$/) || [time]; + + if (timeString.length > 1) { + // If time format correct + timeString = timeString.slice(1); // Remove full string match value + timeString[5] = +timeString[0] < 12 ? ' AM' : ' PM'; // Set AM/PM + timeString[0] = +timeString[0] % 12 || 12; // Adjust hours + } + return timeString.join(''); // return adjusted time or original string +} diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index fe981266..b71dbcb4 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -14,10 +14,11 @@ jest.mock('@/helpers/layout-helper.js', () => jest.fn()); jest.mock('@/helpers/cms-content-helper', () => ({ fetchCmsContentForPage: jest.fn() })); +const wordingText = 'wording Text {custom:address}'; const mockMixin = { methods: { - getCmsContent: jest.fn().mockImplementation(() => ''), + getCmsContent: jest.fn().mockImplementation(() => wordingText), setCmsContent: jest.fn() } }; @@ -33,6 +34,32 @@ const headerStub = { render: () => {} }; +const initialStore = { + order: { + schedule: { + date: '2024-03-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + address: '123 Test Way', + address2: '#1', + city: 'Mesa', + state: 'AZ', + zipCode: '12345', + appointmentType: 'Inshop', + provider: { + address: { + streetAddress: '123 Safelite Street', + city: 'Mesa', + state: 'AZ', + zipCode: '12345' + } + } + } + } +}; + function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) { const mountOptions = getMountOptions({ router: { @@ -75,7 +102,7 @@ describe('OrderConfirmation.vue', () => { describe('Rendering', () => { test('Should render Site Header', () => { // Arrange - const { wrapper } = getMountedComponent({}); + const { wrapper } = getMountedComponent(initialStore); // Act const siteHeader = wrapper.findComponent(headerStub); @@ -85,13 +112,21 @@ describe('OrderConfirmation.vue', () => { }); test('If Advanced flow, should display Site Footer', () => { // Arrange - const carrierReturnUrl = 'testURL'; - const initialStore = { + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00' + }, + serviceLocation: { + appointmentType: 'Inshop' + } + }, issConfig: { - successReturnURL: carrierReturnUrl + successReturnURL: 'testURL' } }; - const { wrapper } = getMountedComponent(initialStore); + const { wrapper } = getMountedComponent(testStore); // Act const siteFooter = wrapper.findComponent({ ref: 'siteFooter' }); @@ -101,7 +136,7 @@ describe('OrderConfirmation.vue', () => { }); test('If Essential flow, should not display Site Footer', () => { // Arrange - const { wrapper } = getMountedComponent(); + const { wrapper } = getMountedComponent(initialStore); // Act const siteFooter = wrapper.findComponent({ ref: 'siteFooter' }); @@ -114,12 +149,21 @@ describe('OrderConfirmation.vue', () => { test('If Advanced flow, forward button action navigates to carrier URL', () => { // Arrange const carrierReturnUrl = 'testURL'; - const initialStore = { + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00' + }, + serviceLocation: { + appointmentType: 'Inshop' + } + }, issConfig: { successReturnURL: carrierReturnUrl } }; - const { wrapper } = getMountedComponent(initialStore); + const { wrapper } = getMountedComponent(testStore); // Act wrapper.vm.forwardButtonAction(); @@ -128,4 +172,157 @@ describe('OrderConfirmation.vue', () => { expect(wrapper.vm.$router.navigateToExternalUrl).toHaveBeenCalledWith(carrierReturnUrl); }); }); + describe('Computed properties', () => { + test('appointmentDateFormatted should return date in expected format', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.appointmentDateFormatted; + + // Assert + expect(testValue).toEqual('Friday, March 1'); + }); + test('appointmentTimeFormatted should return Mobile time in expected format', () => { + // Arrange + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + appointmentType: 'Mobile' + } + } + }; + const { wrapper } = getMountedComponent(testStore); + + // Act + const testValue = wrapper.vm.appointmentTimeFormatted; + + // Assert + expect(testValue).toEqual('Between 9 AM - 10 AM'); + }); + test('appointmentTimeFormatted should return Drop Off time in expected format', () => { + // Arrange + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + appointmentType: 'Drop Off' + } + } + }; + const { wrapper } = getMountedComponent(testStore); + + // Act + const testValue = wrapper.vm.appointmentTimeFormatted; + + // Assert + expect(testValue).toEqual('Drop off before 9:30 AM'); + }); + test('appointmentTimeFormatted should return In Shop time in expected format', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.appointmentTimeFormatted; + + // Assert + expect(testValue).toEqual('at 9:00 AM'); + }); + test('appointmentWordingText should return Mobile text in expected format', () => { + // Arrange + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + address: '123 Test Way', + address2: '#1', + city: 'Mesa', + state: 'AZ', + zipCode: '12345', + appointmentType: 'Mobile' + } + } + }; + const { wrapper } = getMountedComponent(testStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText; + + // Assert + expect(testValue).toEqual('wording Text
    123 Test Way, #1,
    Mesa, AZ 12345
    '); + }); + test('appointmentWordingText should return Drop Off text in expected format', () => { + // Arrange + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + provider: { + address: { + streetAddress: '123 Safelite Street', + city: 'Mesa', + state: 'AZ', + zipCode: '12345' + } + }, + appointmentType: 'Drop Off' + } + } + }; + const { wrapper } = getMountedComponent(testStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText; + + // Assert + expect(testValue).toEqual('wording Text 123 Safelite Street,
    Mesa, AZ 12345'); + }); + test('appointmentWordingText should return In Shop text in expected format', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText; + + // Assert + expect(testValue).toEqual('wording Text 123 Safelite Street,
    Mesa, AZ 12345'); + }); + test('serviceLocationFullAddress should return text in expected format', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.serviceLocationFullAddress; + + // Assert + expect(testValue).toEqual('
    123 Test Way, #1,
    Mesa, AZ 12345
    '); + }); + test('providerFullAddress should return text in expected format', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.providerFullAddress; + + // Assert + expect(testValue).toEqual('123 Safelite Street,
    Mesa, AZ 12345'); + }); + }); }); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 63b028eb..86670ff5 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -8,7 +8,28 @@
    -

    Placeholder for order confirmation page

    +
    + + +
    +
    +
    + + +
    +
    +

    {{ appointmentDateFormatted }}

    +

    {{ appointmentTimeFormatted }}

    +
    +
    +
    +
    // Components import siteHeader from '@/iss-components/site-header/site-header.vue'; +import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue'; // Supporting files import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; @@ -32,11 +54,13 @@ import settleAllPromises from '@/helpers/layout-helper'; import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store'; +import { get12HourTimeFormat, get12HourTimeMobileFormat, convertDateStringToDate } from '@/helpers/date-helper.js'; export default { name: 'order-confirmation', components: { siteHeader, + vehicleBanner, siteFooter, // eslint-disable-next-line vue/no-reserved-component-names Form @@ -67,6 +91,81 @@ export default { }, carrierUrl() { return this.mainStore.issConfig.successReturnURL; + }, + orderConfirmationHeaderText() { + return this.getCmsContent('OrderConfirmationContent', 'HeaderText'); + }, + orderConfirmationImage() { + return this.getCmsContent('OrderConfirmationContent', 'Image'); + }, + appointmentType() { + return this.mainStore.order.serviceLocation.appointmentType.toUpperCase(); + }, + appointmentDate() { + return this.mainStore.order.schedule.date; + }, + appointmentStartTime() { + return this.mainStore.order.schedule.startTime; + }, + appointmentEndTime() { + return this.mainStore.order.schedule.endTime; + }, + appointmentDateFormatted() { + // This conversion ensures we don't get get GMT induced date changes + const dateObject = convertDateStringToDate(this.appointmentDate); + // Ex: Tuesday, April 22 + return dateObject.toLocaleDateString('en-us', { + weekday: 'long', + month: 'long', + day: 'numeric' + }); + }, + appointmentTimeFormatted() { + const formattedTime = this.formatAppointmentTime(this.appointmentType); + return formattedTime; + }, + mobileWordingText() { + return this.getCmsContent('MobileWordingWidget', 'BodyText'); + }, + dropOffAndInShopWordingText() { + return this.getCmsContent('DropOffAndInShopWordingWidget', 'BodyText'); + }, + serviceLocationAddress() { + return this.mainStore.order.serviceLocation.address; + }, + serviceLocationAddress2() { + return this.mainStore.order.serviceLocation.address2; + }, + serviceLocationCity() { + return this.mainStore.order.serviceLocation.city; + }, + serviceLocationState() { + return this.mainStore.order.serviceLocation.state; + }, + serviceLocationZipCode() { + return this.mainStore.order.serviceLocation.zipCode; + }, + serviceLocationFullAddress() { + // eslint-disable-next-line max-len + return `
    ${this.serviceLocationAddress}, ${this.serviceLocationAddress2 ? `${this.serviceLocationAddress2},` : ''}
    ${this.serviceLocationCity}, ${this.serviceLocationState} ${this.serviceLocationZipCode}
    `; + }, + providerAddress() { + return this.mainStore.order.serviceLocation.provider.address.streetAddress; + }, + providerCity() { + return this.mainStore.order.serviceLocation.provider.address.city; + }, + providerState() { + return this.mainStore.order.serviceLocation.provider.address.state; + }, + providerZipCode() { + return this.mainStore.order.serviceLocation.provider.address.zipCode; + }, + providerFullAddress() { + return `${this.providerAddress},
    ${this.providerCity}, ${this.providerState} ${this.providerZipCode}`; + }, + appointmentWordingText() { + return this.formatWordingText(this.appointmentType); } }, mounted() { @@ -77,6 +176,40 @@ export default { methods: { forwardButtonAction() { this.$router.navigateToExternalUrl(this.carrierUrl); + }, + formatAppointmentTime(appointmentType) { + switch (appointmentType) { + case 'MOBILE': + // eslint-disable-next-line max-len + return `Between ${get12HourTimeMobileFormat(this.appointmentStartTime)} - ${get12HourTimeMobileFormat(this.appointmentEndTime)}`; + case 'DROP OFF': + return 'Drop off before 9:30 AM'; + case 'INSHOP': + return `at ${get12HourTimeFormat(this.appointmentStartTime)}`; + default: + return null; + } + }, + formatWordingText(appointmentType) { + switch (appointmentType) { + case 'MOBILE': + return this.mobileWordingText?.replaceAll( + '{custom:address}', + this.serviceLocationFullAddress + ); + case 'DROP OFF': + return this.dropOffAndInShopWordingText?.replaceAll( + '{custom:address}', + this.providerFullAddress + ); + case 'INSHOP': + return this.dropOffAndInShopWordingText?.replaceAll( + '{custom:address}', + this.providerFullAddress + ); + default: + return null; + } } } }; @@ -91,4 +224,34 @@ $page-side-padding: 1.5rem; padding: 0 1.5rem !important; } } + +.text-color--black { + color: $black; +} + +.appointment-details { + margin-bottom: 1.5rem; + padding: 1rem 1.5rem 1.5rem; + box-shadow: 0 3px 10px rgb(0 0 0 / 0.2); + border-radius: 5px; +} + +.appointment-date-time P { + color: $black; + font-size: $h5-font-size; + line-height: map-get($spacers, 6); + margin-bottom: 0.5rem; + + + p { + font-size: map-get($spacers, 4); + line-height: 1.625rem; + font-weight: $font-weight-bold; + } +} + +.appointment-text { + :deep(strong) { + font-weight: $font-weight-bold; + } +} From 1cd4fe9e7d561e503e1adecae6307a6f6c21f188 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Thu, 29 Feb 2024 16:13:21 -0500 Subject: [PATCH 581/674] title case and unit test fixes --- src/layouts/order-confirmation/order-confirmation.spec.js | 6 +++--- src/layouts/order-confirmation/order-confirmation.vue | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index b71dbcb4..590b5c1b 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -292,7 +292,7 @@ describe('OrderConfirmation.vue', () => { const testValue = wrapper.vm.appointmentWordingText; // Assert - expect(testValue).toEqual('wording Text 123 Safelite Street,
    Mesa, AZ 12345'); + expect(testValue).toEqual('wording Text
    123 Safelite Street,
    Mesa, AZ 12345
    '); }); test('appointmentWordingText should return In Shop text in expected format', () => { // Arrange @@ -302,7 +302,7 @@ describe('OrderConfirmation.vue', () => { const testValue = wrapper.vm.appointmentWordingText; // Assert - expect(testValue).toEqual('wording Text 123 Safelite Street,
    Mesa, AZ 12345'); + expect(testValue).toEqual('wording Text
    123 Safelite Street,
    Mesa, AZ 12345
    '); }); test('serviceLocationFullAddress should return text in expected format', () => { // Arrange @@ -322,7 +322,7 @@ describe('OrderConfirmation.vue', () => { const testValue = wrapper.vm.providerFullAddress; // Assert - expect(testValue).toEqual('123 Safelite Street,
    Mesa, AZ 12345'); + expect(testValue).toEqual('
    123 Safelite Street,
    Mesa, AZ 12345
    '); }); }); }); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 86670ff5..38f2dc9e 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -55,6 +55,7 @@ import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store'; import { get12HourTimeFormat, get12HourTimeMobileFormat, convertDateStringToDate } from '@/helpers/date-helper.js'; +import { toTitleCase } from '@/helpers/text-helper.js'; export default { name: 'order-confirmation', @@ -150,10 +151,10 @@ export default { return `
    ${this.serviceLocationAddress}, ${this.serviceLocationAddress2 ? `${this.serviceLocationAddress2},` : ''}
    ${this.serviceLocationCity}, ${this.serviceLocationState} ${this.serviceLocationZipCode}
    `; }, providerAddress() { - return this.mainStore.order.serviceLocation.provider.address.streetAddress; + return toTitleCase(this.mainStore.order.serviceLocation.provider.address.streetAddress); }, providerCity() { - return this.mainStore.order.serviceLocation.provider.address.city; + return toTitleCase(this.mainStore.order.serviceLocation.provider.address.city); }, providerState() { return this.mainStore.order.serviceLocation.provider.address.state; @@ -162,7 +163,8 @@ export default { return this.mainStore.order.serviceLocation.provider.address.zipCode; }, providerFullAddress() { - return `${this.providerAddress},
    ${this.providerCity}, ${this.providerState} ${this.providerZipCode}`; + // eslint-disable-next-line max-len + return `
    ${this.providerAddress},
    ${this.providerCity}, ${this.providerState} ${this.providerZipCode}
    `; }, appointmentWordingText() { return this.formatWordingText(this.appointmentType); From 152a799caae9f03e64ca4411f6a22e6be7a111dc Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 1 Mar 2024 13:50:50 -0500 Subject: [PATCH 582/674] Partial --- src/constants/endpoints.js | 106 ++++++++++------- .../cart-dropdown/cart-dropdown.vue | 47 ++++++-- src/layouts/payment-method/payment-method.vue | 11 +- src/store/paymentStore.js | 112 ++++++++++++++++++ 4 files changed, 217 insertions(+), 59 deletions(-) create mode 100644 src/store/paymentStore.js diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 5f3b1a91..6ac0a793 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -1,190 +1,204 @@ +const baseContentUrl = '/content/api/v1/content'; +const baseLocationUrl = '/location/api/v1/location'; +const baseScheduleUrl = '/schedule/api/v1/schedule'; +const basePartsUrl = '/parts/api/v1/parts'; +const baseVehicleUrl = '/vehicle/api/v1/vehicle'; +const basePriceUrl = '/price/api/v1/price'; +const baseAnalyticsUrl = '/analytics/api/v1/analytics'; +const baseExperimentsUrl = '/experiments/api/v1/experiments'; +const baseClientAuthUrl = '/clientauth/api/v1/clientauth'; +const baseOrderUrl = '/order/api/v1/order'; +const baseCoverageUrl = '/coverage/api/v1/coverage'; +const baseAccountUrl = '/account/api/v1/account/'; + const endpoints = Object.freeze({ GetRouteInfo: { - url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/RouteInfo`, + url: (applicationAbbreviation) => `${baseContentUrl}/${applicationAbbreviation}/RouteInfo`, method: 'POST' }, GetHomepageInfo: { - url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/HomepageInfo`, + url: (applicationAbbreviation) => `${baseContentUrl}/${applicationAbbreviation}/HomepageInfo`, method: 'GET' }, GetPageData: { - url: (applicationAbbreviation, pageName) => `/content/api/v1/content/${applicationAbbreviation}/${pageName}`, + url: (applicationAbbreviation, pageName) => `${baseContentUrl}/${applicationAbbreviation}/${pageName}`, method: 'GET' }, GetAlertReasons: { - url: '/location/api/v1/location/alert-reasons', + url: `${baseLocationUrl}/alert-reasons`, method: 'GET' }, GetShopTimeSlots: { - url: '/schedule/api/v1/schedule/shop-time-slots', + url: `${baseScheduleUrl}/shop-time-slots`, method: 'POST' }, GetMobileTimeSlots: { - url: '/schedule/api/v1/schedule/mobile-time-slots', + url: `${baseScheduleUrl}/mobile-time-slots`, method: 'POST' }, GetMobilePremiumFee: { - url: '/parts/api/v1/parts/mobile-premium-fee', + url: `${basePartsUrl}/mobile-premium-fee`, method: 'GET' }, GetVehicleYears: { - url: '/vehicle/api/v1/vehicle/years', + url: `${baseVehicleUrl}/years`, method: 'GET' }, GetVehicleMakes: { - url: '/vehicle/api/v1/vehicle/makes/', + url: `${baseVehicleUrl}/makes/`, method: 'GET' }, GetVehicleModels: { - url: '/vehicle/api/v1/vehicle/models', + url: `${baseVehicleUrl}/models`, method: 'GET' }, GetVehicleStyles: { - url: '/vehicle/api/v1/vehicle/styles', + url: `${baseVehicleUrl}/styles`, method: 'GET' }, GetDamageOptions: { - url: '/parts/api/v1/parts/damage-options', + url: `${basePartsUrl}/damage-options`, method: 'GET' }, GetPartsOrQuestions: { - url: '/parts/api/v1/parts/parts-or-questions', + url: `${basePartsUrl}/parts-or-questions`, method: 'POST' }, GetParts: { - url: '/parts/api/v1/parts/parts', + url: `${basePartsUrl}/parts`, method: 'POST' }, + // TODO finish GetInsurancePriceOrderItems: { - url: '/price/api/v1/price/order-items-with-insurance-pricing', + url: () => `${basePriceUrl}/order-items-with-insurance-pricing`, method: 'GET' }, GetPriceOrderItems: { - url: '/price/api/v1/price/order-items', + url: `${basePriceUrl}/order-items`, method: 'GET' }, GetProviders: { - url: '/location/api/v1/location/providers', + url: `${baseLocationUrl}/providers`, method: 'GET' }, GetCapabilityQuestions: { - url: '/parts/api/v1/parts/capability-questions', + url: `${basePartsUrl}/capability-questions`, method: 'GET' }, GetPartFromCapabilityAnswer: { - url: '/parts/api/v1/parts/part-from-capability-answer', + url: `${basePartsUrl}/part-from-capability-answer`, method: 'POST' }, GetWipers: { - url: '/parts/api/v1/parts/wipers', + url: `${basePartsUrl}/wipers`, method: 'GET' }, GetRainDefense: { - url: '/parts/api/v1/parts/rain-defense', + url: `${basePartsUrl}/rain-defense`, method: 'GET' }, GetSupportingItems: { - url: '/parts/api/v1/parts/supporting-items', + url: `${basePartsUrl}/supporting-items`, method: 'POST' }, GetMobileFeePart: { - url: '/parts/api/v1/parts/mobile-fee', + url: `${basePartsUrl}/mobile-fee`, method: 'GET' }, GetServiceabilityDetails: { - url: '/location/api/v1/location/serviceability-details', + url: `${baseLocationUrl}/serviceability-details`, method: 'GET' }, GetVehicle: { - url: '/vehicle/api/v1/vehicle/lookup', + url: `${baseVehicleUrl}/lookup`, method: 'GET' }, GetAccountInfo: { - url: '/account/api/v1/account/', + url: baseAccountUrl, method: 'GET' }, LogExperimentExposureIfAssigned: { - url: '/experiments/api/v1/experiments/log-exposure', + url: `${baseExperimentsUrl}/log-exposure`, method: 'POST' }, LogPageView: { - url: '/analytics/api/v1/analytics/log-page-view', + url: `${baseAnalyticsUrl}/log-page-view`, method: 'POST' }, LogCustomEvent: { - url: '/analytics/api/v1/analytics/log-custom-event', + url: `${baseAnalyticsUrl}/log-custom-event`, method: 'POST' }, LookupVehicleByVin: { - url: '/vehicle/api/v1/vehicle/lookup', + url: `${baseVehicleUrl}/lookup`, method: 'POST' }, LookupVinByAddress: { - url: '/vehicle/api/v1/vehicle/lookup-vin-by-address', + url: `${baseVehicleUrl}/lookup-vin-by-address`, method: 'POST' }, LookupVinByPlate: { - url: '/vehicle/api/v1/vehicle/lookup-vin-by-plate', + url: `${baseVehicleUrl}/lookup-vin-by-plate`, method: 'POST' }, InitializeSession: { - url: '/analytics/api/v1/analytics/initialize', + url: `${baseAnalyticsUrl}/initialize`, method: 'POST' }, GetExperimentsByUser: { - url: '/analytics/api/v1/analytics/get-experiments', + url: `${baseAnalyticsUrl}/get-experiments`, method: 'GET' }, RunExperimentsForTrigger: { - url: '/experiments/api/v1/experiments/run', + url: `${baseExperimentsUrl}/run`, method: 'POST' }, ValidateZip: { - url: '/location/api/v1/location/zip', + url: `${baseLocationUrl}/zip`, method: 'GET' }, GooglePlaces: { url: (apiKey) => `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places` }, ValidateClientTag: { - url: '/clientauth/api/v1/clientauth/validate-client-tag', + url: `${baseClientAuthUrl}/validate-client-tag`, method: 'GET' }, ValidateClientSignature: { - url: '/clientauth/api/v1/clientauth/validate-client-signature', + url: `${baseClientAuthUrl}/validate-client-signature`, method: 'POST' }, IsVinbyAddressPermissible: { - url: '/vehicle/api/v1/vehicle/is-vin-by-address-permissible', + url: `${baseVehicleUrl}/is-vin-by-address-permissible`, method: 'Get' }, CoveragePolicyInfo: { - url: '/coverage/api/v1/coverage/policy-information', + url: `${baseCoverageUrl}/policy-information`, method: 'POST' }, RegisterClaim: { - url: '/coverage/api/v1/coverage/register-claim', + url: `${baseCoverageUrl}/register-claim`, method: 'POST' }, SaveSession: { - url: '/order/api/v1/order/save-session/iss', + url: `${baseOrderUrl}/save-session/iss`, method: 'POST' }, LoadSession: { - url: '/order/api/v1/order/load-session', + url: `${baseOrderUrl}/load-session`, method: 'POST' }, DuplicateSearch: { // eslint-disable-next-line max-len - url: (accountNumber, policyNumber, dateOfLoss) => `/order/api/v1/order/duplicate-check/${accountNumber}/${policyNumber}/${dateOfLoss}`, + url: (accountNumber, policyNumber, dateOfLoss) => `${baseOrderUrl}/duplicate-check/${accountNumber}/${policyNumber}/${dateOfLoss}`, method: 'GET' }, FinalDeductible: { - url: '/coverage/api/v1/coverage/final-deductible', + url: `${baseCoverageUrl}/final-deductible`, method: 'POST' }, GetPaymentSignature: { - url: '/order/api/v1/order/sign', + url: `${baseOrderUrl}/sign`, method: 'POST' } }); diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index e9b23408..4e2caae7 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -54,7 +54,8 @@ export default { showAsPaid: Boolean, amountDueLabel: String, deductibleLabel: String, - basePriceLabel: String + basePriceLabel: String, + baseServiceLineItems: Array }, data() { return { @@ -69,19 +70,9 @@ export default { deductible() { return useMainStore().order.currentDeductible; }, - availableLineItems() { - // TODO make real - return [ - { - kitPrice: 1, - laborAmount: 2, - sellingPrice: 3 - } - ]; - }, // TODO share with claim registration page baseServicePrice() { - return this.availableLineItems + return this.baseServiceLineItems .reduce( (accumulator, lineItem) => accumulator + this.getTotalLineItemPrice(lineItem), 0 @@ -105,6 +96,10 @@ export default { return this.showAsPaid ? 0 : this.subTotal + this.salesTax; + }, + clonedGlassParts() { + const valueToClone = useMainStore().order.lineItems.glassParts ?? []; + return JSON.parse(JSON.stringify(valueToClone)) ?? []; } }, methods: { @@ -122,6 +117,34 @@ export default { return this.isUnverified && this.showDeductibleLineItem ? VERIFYING_COVERAGE : this.getFormattedAmount(amount); + }, + async temporaryMethod() { + // TODO need supporting items + // TODO need pricing results from getPriceOrderItems + // get base service line items + const supportingItems = await useMainStore().getSupportingItems(); + supportingItems.then((data) => { + // TODO do something + }); + const availableLineItems = [ + ...(supportingItems ?? []), + ...(this.clonedGlassParts) + ]; + + let pricingResults = []; + if (useMainStore().policy.policyLookupSuccessful && useMainStore().vehicle.policyVehicleId >= 0) { + // await useMainStore().getFinalDeductible(); + // I don't think we need to perform the getFinalDeductible call + // policy data is set in policy.policyData + pricingResults = await useMainStore().getPriceOrderItems(availableLineItems) + } + + // Call the "next" function to complete the transition to this page. + // vm.setSupportingItems(supportingItems); + // // eslint-disable-next-line no-param-reassign + // vm.availableLineItems = pricingResults; + // vm.initializeComponent(availableLineItems); + return []; } } }; diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index efdbb703..d7c6b0df 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -23,7 +23,8 @@ :showAsPaid="false" :amountDueLabel="amountDueText" :deductibleLabel="deductibleLabel" - :basePriceLabel="basePriceLabel" /> + :basePriceLabel="basePriceLabel" + :baseServiceLineItems="baseServiceLineItems" />
    Pia Alert Placeholder
    { + let queryStringSnippet = `&LineItems[${index}].partNumber=${lineItem.partNumber}`; + if (lineItem.childParts) { + queryStringSnippet += getLineItemQueryStringForPricing(lineItem.childParts); + } + + return queryStringSnippet; + }).join(''); +} + +function addPricesToLineItems(lineItems, pricingLineItems) { + return lineItems.map((lineItem) => { + const updatedLineItem = lineItem; + updatedLineItem.childParts = lineItem.childParts.map((childItem) => addPricesToLineItems(childItem, pricingLineItems)); + + const lineItemIndex = pricingLineItems.findIndex((pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber); + + if (lineItemIndex > -1) { + const pricedLineItem = pricingLineItems[lineItemIndex]; + updatedLineItem.laborAmount = pricedLineItem.laborAmount; + updatedLineItem.sellingPrice = pricedLineItem.sellingPrice; + updatedLineItem.kitPrice = pricedLineItem.kitPrice; + } + return updatedLineItem; + }); +} + +const usePaymentStore = defineStore({ + id: paymentStoreId, + state: () => ({ + deductible: null, + coverageStatus: coverageStatuses.PENDING, + isITAC: false, + isNoComp: false, + baseServiceLineItems: null, + supportingItems: null + }), + getters: {}, + actions: { + setBaseServiceLineItems() { + this.baseServiceLineItems = []; + }, + 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; + }, + async setSupportingItems() { + const glassPartsArray = useMainStore().lineItems.glassParts ?? []; + const { carId } = useMainStore().vehicle; + const { isRepair, numberOfChips } = useMainStore().damage; + + this.supportingItems = await 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 + } + }); + } + }, + persist: true +}); + +export { usePaymentStore }; From 4d0a3524413cf9c36157228f105200234e0b23fa Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 1 Mar 2024 13:54:33 -0500 Subject: [PATCH 583/674] Forgot to save --- .../cart-dropdown/cart-dropdown.vue | 6 ---- .../coverage-statement/coverage-statement.vue | 9 ++++- src/store/paymentStore.js | 33 ++++++++----------- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/iss-components/cart-dropdown/cart-dropdown.vue b/src/iss-components/cart-dropdown/cart-dropdown.vue index 4e2caae7..e29ed819 100644 --- a/src/iss-components/cart-dropdown/cart-dropdown.vue +++ b/src/iss-components/cart-dropdown/cart-dropdown.vue @@ -138,12 +138,6 @@ export default { // policy data is set in policy.policyData pricingResults = await useMainStore().getPriceOrderItems(availableLineItems) } - - // Call the "next" function to complete the transition to this page. - // vm.setSupportingItems(supportingItems); - // // eslint-disable-next-line no-param-reassign - // vm.availableLineItems = pricingResults; - // vm.initializeComponent(availableLineItems); return []; } } diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index bcdc76cb..1e5efb02 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -179,7 +179,13 @@ export default { await useMainStore().getFinalDeductible(); pricingResults = await useMainStore().getPriceOrderItems(availableLineItems) .catch((err) => { - useMainStore().setBailout(to, bailoutMessage.pricingResponseError(availableLineItems.map((li) => li.partNumber), { code: err.code, message: err.message, data: err.data })); + useMainStore().setBailout( + to, + bailoutMessage.pricingResponseError( + availableLineItems.map((li) => li.partNumber), + { code: err.code, message: err.message, data: err.data } + ) + ); hasBailedOut = true; next(`/?issPage=${issPageValues.BAILOUT_PAGE}`); }); @@ -306,6 +312,7 @@ export default { isRepair() { return useMainStore().order.damage.isRepair; }, + // TODO share totalServicePrice() { let total = 0; this.availableLineItems.forEach((lineItem) => { diff --git a/src/store/paymentStore.js b/src/store/paymentStore.js index 237c765e..21a74436 100644 --- a/src/store/paymentStore.js +++ b/src/store/paymentStore.js @@ -18,10 +18,10 @@ function getLineItemQueryStringForPricing(lineItems) { }).join(''); } -function addPricesToLineItems(lineItems, pricingLineItems) { +function getPricedLineItems(lineItems, pricingLineItems) { return lineItems.map((lineItem) => { const updatedLineItem = lineItem; - updatedLineItem.childParts = lineItem.childParts.map((childItem) => addPricesToLineItems(childItem, pricingLineItems)); + updatedLineItem.childParts = lineItem.childParts.map((childItem) => getPricedLineItems(childItem, pricingLineItems)); const lineItemIndex = pricingLineItems.findIndex((pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber); @@ -51,26 +51,19 @@ const usePaymentStore = defineStore({ this.baseServiceLineItems = []; }, 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 { zipCode, zipCodeCtu } = useMainStore().order.serviceLocation; const availableLineItemsFormattedForRequest = getLineItemQueryStringForPricing(availableLineItems); - const deductibleToUse = this.order.currentDeductible ?? 0; + const deductibleToUse = this.currentDeductible ?? 0; let queryString = - `ParentAccountNumber=${this.order.accountNumber}` - + `&CTU=${ctuToUse}` - + `&Deductible=${deductibleToUse}` - + `&ZipCode=${zipCodeToUse}` - + `${availableLineItemsFormattedForRequest}`; + `ParentAccountNumber=${useMainStore().order.accountNumber}` + + `&CTU=${zipCodeCtu}` + + `&Deductible=${deductibleToUse}` + + `&ZipCode=${zipCode}` + + `${availableLineItemsFormattedForRequest}`; - const lineItemServerData = this.order.lineItems?.serverData; - if (lineItemServerData) { - queryString += `&ServerData=${encodeURIComponent(lineItemServerData)}`; - } + const lineItemServerData = useMainStore().lineItems?.serverData; + queryString += lineItemServerData ? `&ServerData=${encodeURIComponent(lineItemServerData)}` : ''; const response = await globalMethods .callHttpClient({ @@ -82,8 +75,8 @@ const usePaymentStore = defineStore({ }); if (response.data?.lineItems) { - const retAvailableLineItems = addPricesToLineItems(availableLineItems, response.data.lineItems); - return retAvailableLineItems; + const returnedAvailableLineItems = getPricedLineItems(availableLineItems, response.data.lineItems); + return returnedAvailableLineItems; } return availableLineItems; }, From 651bf932cc33db4285081d5ee5d4e790399b655d Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 1 Mar 2024 17:27:45 -0500 Subject: [PATCH 584/674] Simple condensing of common endpoint string --- src/constants/endpoints.js | 105 +++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 46 deletions(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 65526ce9..8bd893e9 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -1,190 +1,203 @@ +const CONTENT_BASE_URL = '/content/api/v1/content'; +const LOCATION_BASE_URL = '/location/api/v1/location'; +const SCHEDULE_BASE_URL = '/schedule/api/v1/schedule'; +const PARTS_BASE_URL = '/parts/api/v1/parts'; +const VEHICLE_BASE_URL = '/vehicle/api/v1/vehicle'; +const PRICE_BASE_URL = '/price/api/v1/price'; +const ACCOUNT_BASE_URL = '/account/api/v1/account'; +const EXPERIMENTS_BASE_URL = '/experiments/api/v1/experiments'; +const ANALYTICS_BASE_URL = '/analytics/api/v1/analytics'; +const CLIENT_AUTH_BASE_URL = '/clientauth/api/v1/clientauth'; +const COVERAGE_BASE_URL = '/coverage/api/v1/coverage'; +const ORDER_BASE_URL = '/order/api/v1/order'; + const endpoints = Object.freeze({ GetRouteInfo: { - url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/RouteInfo`, + url: (applicationAbbreviation) => `${CONTENT_BASE_URL}/${applicationAbbreviation}/RouteInfo`, method: 'POST' }, GetHomepageInfo: { - url: (applicationAbbreviation) => `/content/api/v1/content/${applicationAbbreviation}/HomepageInfo`, + url: (applicationAbbreviation) => `${CONTENT_BASE_URL}/${applicationAbbreviation}/HomepageInfo`, method: 'GET' }, GetPageData: { - url: (applicationAbbreviation, pageName) => `/content/api/v1/content/${applicationAbbreviation}/${pageName}`, + url: (applicationAbbreviation, pageName) => `${CONTENT_BASE_URL}/${applicationAbbreviation}/${pageName}`, method: 'GET' }, GetAlertReasons: { - url: '/location/api/v1/location/alert-reasons', + url: `${LOCATION_BASE_URL}/alert-reasons`, method: 'GET' }, GetShopTimeSlots: { - url: '/schedule/api/v1/schedule/shop-time-slots', + url: `${SCHEDULE_BASE_URL}/shop-time-slots`, method: 'POST' }, GetMobileTimeSlots: { - url: '/schedule/api/v1/schedule/mobile-time-slots', + url: `${SCHEDULE_BASE_URL}/mobile-time-slots`, method: 'POST' }, GetMobilePremiumFee: { - url: '/parts/api/v1/parts/mobile-premium-fee', + url: `${PARTS_BASE_URL}/mobile-premium-fee`, method: 'GET' }, GetVehicleYears: { - url: '/vehicle/api/v1/vehicle/years', + url: `${VEHICLE_BASE_URL}/years`, method: 'GET' }, GetVehicleMakes: { - url: '/vehicle/api/v1/vehicle/makes/', + url: `${VEHICLE_BASE_URL}/makes/`, method: 'GET' }, GetVehicleModels: { - url: '/vehicle/api/v1/vehicle/models', + url: `${VEHICLE_BASE_URL}/models`, method: 'GET' }, GetVehicleStyles: { - url: '/vehicle/api/v1/vehicle/styles', + url: `${VEHICLE_BASE_URL}/styles`, method: 'GET' }, GetDamageOptions: { - url: '/parts/api/v1/parts/damage-options', + url: `${PARTS_BASE_URL}/damage-options`, method: 'GET' }, GetPartsOrQuestions: { - url: '/parts/api/v1/parts/parts-or-questions', + url: `${PARTS_BASE_URL}/parts-or-questions`, method: 'POST' }, GetParts: { - url: '/parts/api/v1/parts/parts', + url: `${PARTS_BASE_URL}/parts`, method: 'POST' }, GetInsurancePriceOrderItems: { - url: '/price/api/v1/price/order-items-with-insurance-pricing', + url: `${PRICE_BASE_URL}/order-items-with-insurance-pricing`, method: 'GET' }, GetPriceOrderItems: { - url: '/price/api/v1/price/order-items', + url: `${PRICE_BASE_URL}/order-items`, method: 'GET' }, GetProviders: { - url: '/location/api/v1/location/providers', + url: `${LOCATION_BASE_URL}/providers`, method: 'GET' }, GetCapabilityQuestions: { - url: '/parts/api/v1/parts/capability-questions', + url: `${PARTS_BASE_URL}/capability-questions`, method: 'GET' }, GetPartFromCapabilityAnswer: { - url: '/parts/api/v1/parts/part-from-capability-answer', + url: `${PARTS_BASE_URL}/part-from-capability-answer`, method: 'POST' }, GetWipers: { - url: '/parts/api/v1/parts/wipers', + url: `${PARTS_BASE_URL}/wipers`, method: 'GET' }, GetRainDefense: { - url: '/parts/api/v1/parts/rain-defense', + url: `${PARTS_BASE_URL}/rain-defense`, method: 'GET' }, GetSupportingItems: { - url: '/parts/api/v1/parts/supporting-items', + url: `${PARTS_BASE_URL}/supporting-items`, method: 'POST' }, GetMobileFeePart: { - url: '/parts/api/v1/parts/mobile-fee', + url: `${PARTS_BASE_URL}/mobile-fee`, method: 'GET' }, GetServiceabilityDetails: { - url: '/location/api/v1/location/serviceability-details', + url: `${LOCATION_BASE_URL}/serviceability-details`, method: 'GET' }, GetVehicle: { - url: '/vehicle/api/v1/vehicle/lookup', + url: `${VEHICLE_BASE_URL}/lookup`, method: 'GET' }, GetAccountInfo: { - url: '/account/api/v1/account/', + url: `${ACCOUNT_BASE_URL}/`, method: 'GET' }, LogExperimentExposureIfAssigned: { - url: '/experiments/api/v1/experiments/log-exposure', + url: `${EXPERIMENTS_BASE_URL}/log-exposure`, method: 'POST' }, LogPageView: { - url: '/analytics/api/v1/analytics/log-page-view', + url: `${ANALYTICS_BASE_URL}/log-page-view`, method: 'POST' }, LogCustomEvent: { - url: '/analytics/api/v1/analytics/log-custom-event', + url: `${ANALYTICS_BASE_URL}/log-custom-event`, method: 'POST' }, LookupVehicleByVin: { - url: '/vehicle/api/v1/vehicle/lookup', + url: `${VEHICLE_BASE_URL}/lookup`, method: 'POST' }, LookupVinByAddress: { - url: '/vehicle/api/v1/vehicle/lookup-vin-by-address', + url: `${VEHICLE_BASE_URL}/lookup-vin-by-address`, method: 'POST' }, LookupVinByPlate: { - url: '/vehicle/api/v1/vehicle/lookup-vin-by-plate', + url: `${VEHICLE_BASE_URL}/lookup-vin-by-plate`, method: 'POST' }, InitializeSession: { - url: '/analytics/api/v1/analytics/initialize', + url: `${ANALYTICS_BASE_URL}/initialize`, method: 'POST' }, GetExperimentsByUser: { - url: '/analytics/api/v1/analytics/get-experiments', + url: `${ANALYTICS_BASE_URL}/get-experiments`, method: 'GET' }, RunExperimentsForTrigger: { - url: '/experiments/api/v1/experiments/run', + url: `${EXPERIMENTS_BASE_URL}/run`, method: 'POST' }, ValidateZip: { - url: '/location/api/v1/location/zip', + url: `${LOCATION_BASE_URL}/zip`, method: 'GET' }, GooglePlaces: { url: (apiKey) => `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places` }, ValidateClientTag: { - url: '/clientauth/api/v1/clientauth/validate-client-tag', + url: `${CLIENT_AUTH_BASE_URL}/validate-client-tag`, method: 'GET' }, ValidateClientSignature: { - url: '/clientauth/api/v1/clientauth/validate-client-signature', + url: `${CLIENT_AUTH_BASE_URL}/validate-client-signature`, method: 'POST' }, IsVinbyAddressPermissible: { - url: '/vehicle/api/v1/vehicle/is-vin-by-address-permissible', + url: `${VEHICLE_BASE_URL}/is-vin-by-address-permissible`, method: 'Get' }, CoveragePolicyInfo: { - url: '/coverage/api/v1/coverage/policy-information', + url: `${COVERAGE_BASE_URL}/policy-information`, method: 'POST' }, RegisterClaim: { - url: '/coverage/api/v1/coverage/register-claim', + url: `${COVERAGE_BASE_URL}/register-claim`, method: 'POST' }, SaveSession: { - url: '/order/api/v1/order/save-session/iss', + url: `${ORDER_BASE_URL}/save-session/iss`, method: 'POST' }, LoadSession: { - url: '/order/api/v1/order/load-session/iss', + url: `${ORDER_BASE_URL}/load-session/iss`, method: 'POST' }, DuplicateSearch: { // eslint-disable-next-line max-len - url: (accountNumber, policyNumber, dateOfLoss) => `/order/api/v1/order/duplicate-check/${accountNumber}/${policyNumber}/${dateOfLoss}`, + url: (accountNumber, policyNumber, dateOfLoss) => `${ORDER_BASE_URL}/duplicate-check/${accountNumber}/${policyNumber}/${dateOfLoss}`, method: 'GET' }, FinalDeductible: { - url: '/coverage/api/v1/coverage/final-deductible', + url: `${COVERAGE_BASE_URL}/final-deductible`, method: 'POST' }, GetPaymentSignature: { - url: '/order/api/v1/order/sign', + url: `${ORDER_BASE_URL}/sign`, method: 'POST' } }); From ec85a33693f822a19782f8c2884dfba2e28a5fd1 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 1 Mar 2024 17:57:59 -0500 Subject: [PATCH 585/674] Removing unnecessary --- src/layouts/coverage-statement/coverage-statement.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index f5ab548d..02848781 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -128,7 +128,6 @@ import baseFormMixin from '@/mixins/base-form-mixin.js'; import navigationScenarios from '@/router/router-constants/navigation-scenarios.js'; import routerParams from '@/router/router-constants/router-params'; import issPageValues from '@/router/router-constants/issPage-values'; -import bailoutCode from '@/constants/bailoutCode'; import bailoutMessage from '@/constants/bailoutMessage'; export default { @@ -405,7 +404,6 @@ export default { ); } }, - processIfStatements, getHeaderTextFromCms(cmsWidgetName) { const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); return this.processIfStatements(header, 'custom', this.getCustomValueFromString); From 5ac9970d655bc661c2858ac18538591c0b8f6ae4 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Fri, 1 Mar 2024 18:01:23 -0500 Subject: [PATCH 586/674] Getting rid of mainStore data property --- .../coverage-statement/coverage-statement.vue | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 02848781..51ad2a5d 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -177,7 +177,14 @@ export default { await useMainStore().getFinalDeductible(); pricingResults = await useMainStore().getPriceOrderItems(availableLineItems) .catch((err) => { - useMainStore().setBailout(to, bailoutMessage.pricingResponseError(availableLineItems.map((li) => li.partNumber), { code: err.code, message: err.message, data: err.data })); + useMainStore() + .setBailout( + to, + bailoutMessage.pricingResponseError( + availableLineItems.map((li) => li.partNumber), + { code: err.code, message: err.message, data: err.data } + ) + ); hasBailedOut = true; next(`/?issPage=${issPageValues.BAILOUT_PAGE}`); }); @@ -198,10 +205,6 @@ export default { }); } }, - setup() { - const mainStore = useMainStore(); - return { mainStore }; - }, data() { return { availableLineItems: [], @@ -368,7 +371,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { - this.mainStore.saveSupportingItems(this.supportingItems); + useMainStore().saveSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -378,7 +381,7 @@ export default { } else if (this.verifiedITAC || this.verifiedNoComp) { useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); if (this.selectedProvider === 'Safelite') { - this.mainStore.saveSupportingItems(this.supportingItems); + useMainStore().saveSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route, @@ -386,7 +389,7 @@ export default { { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else { - this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); + useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, this.$route, @@ -395,7 +398,7 @@ export default { ); } } else { - this.mainStore.setBailout(this.$router.currentRoute, bailoutMessage.coverageStatementInvalidState()); + useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.coverageStatementInvalidState()); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE, this.$route, @@ -406,23 +409,23 @@ export default { }, getHeaderTextFromCms(cmsWidgetName) { const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); - return this.processIfStatements(header, 'custom', this.getCustomValueFromString); + return processIfStatements(header, 'custom', this.getCustomValueFromString); }, getSubheaderTextFromCms(cmsWidgetName) { const subHeader = this.getCmsContent(cmsWidgetName, 'SubHeaderText'); - return this.processIfStatements(subHeader, 'custom', this.getCustomValueFromString); + return processIfStatements(subHeader, 'custom', this.getCustomValueFromString); }, getBodyTextFromCms(cmsWidgetName) { const bodyText = this.getCmsContent(cmsWidgetName, 'BodyText'); - return this.processIfStatements(bodyText, 'custom', this.getCustomValueFromString); + return processIfStatements(bodyText, 'custom', this.getCustomValueFromString); }, getSecondaryTextFromCms(cmsWidgetName) { const secondaryText = this.getCmsContent(cmsWidgetName, 'SecondaryText'); - return this.processIfStatements(secondaryText, 'custom', this.getCustomValueFromString); + return processIfStatements(secondaryText, 'custom', this.getCustomValueFromString); }, getExplantoryTextFromCms(cmsWidgetName) { const explanatoryText = this.getCmsContent(cmsWidgetName, 'BodyText'); - return this.processIfStatements(explanatoryText, 'custom', this.getCustomValueFromString); + return processIfStatements(explanatoryText, 'custom', this.getCustomValueFromString); }, getCustomValueFromString(str) { switch (str) { From 090188ed64ec6b66fa6cc53874b1e09f1ce6c70f Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 13:28:39 -0500 Subject: [PATCH 587/674] Partial --- .../coverage-statement/coverage-statement.vue | 191 +++++++++--------- src/store/index.js | 7 +- 2 files changed, 98 insertions(+), 100 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 51ad2a5d..80e1665f 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -38,7 +38,7 @@ {{ formattedDeductible }}
    {{ formattedServicePrice }}
    @@ -53,8 +53,8 @@ ref="verifiedITACAlert" class="mb-5" cmsWidgetName="VerifiedITACAlert" - :manualHeadline="verifiedITACAlertHeader" - :manualCopy="verifiedITACAlertBody" + :manualHeadline="verifiedItacAlertHeader" + :manualCopy="verifiedItacAlertBody" alertClass="alert-success" :isDismissible="false"> @@ -67,18 +67,18 @@ v-html="nextStepsBody">
    @@ -88,7 +88,7 @@ cmsWidgetName="SiteFooterWidget" :isForwardActionDisabled="!meta.valid" @backClicked="navigateBackByVehicleQuestions" - @forwardClicked="forwardButtonAction" /> + @forwardClicked="navigateForward" />
    @@ -129,6 +129,9 @@ import navigationScenarios from '@/router/router-constants/navigation-scenarios. import routerParams from '@/router/router-constants/router-params'; import issPageValues from '@/router/router-constants/issPage-values'; import bailoutMessage from '@/constants/bailoutMessage'; +import widgetFields from '@/constants/cms-widget-fields.js'; + +const SAFELITE_PROVIDER = 'Safelite'; export default { name: 'coverage-statement', @@ -163,8 +166,8 @@ export default { ]; const resultMap = await settleAllPromises(promiseResultMap); - const clonedGlassParts = useMainStore().order.lineItems.glassParts - ? JSON.parse(JSON.stringify(useMainStore().order.lineItems.glassParts)) + const clonedGlassParts = useMainStore().lineItems.glassParts + ? JSON.parse(JSON.stringify(useMainStore().lineItems.glassParts)) : []; const availableLineItems = [ ...(resultMap.supportingItems ?? []), @@ -173,7 +176,7 @@ export default { let hasBailedOut = false; let pricingResults = []; - if (useMainStore().order.policy.policyLookupSuccessful && useMainStore().order.vehicle.policyVehicleId >= 0) { + if (useMainStore().policy.policyLookupSuccessful && useMainStore().vehicle.policyVehicleId >= 0) { await useMainStore().getFinalDeductible(); pricingResults = await useMainStore().getPriceOrderItems(availableLineItems) .catch((err) => { @@ -196,9 +199,9 @@ export default { vm.setCmsContent(resultMap.cmsContent); vm.setSupportingItems(resultMap.supportingItems); // eslint-disable-next-line no-param-reassign - vm.availableLineItems = pricingResults; + vm.setAvailableLineItems(pricingResults); vm.$refs.loadingModal.showModal(); - vm.initializeComponent(availableLineItems); + vm.initializeComponent(); if (!vm.unverified) { useMainStore().disableKeyFields(); } @@ -206,7 +209,14 @@ export default { } }, data() { + const { isRepair } = useMainStore().damage; + const { policyLookupSuccessful, noCoverage } = useMainStore().policy; + const { currentDeductible } = useMainStore().order.currentDeductible; return { + isRepair, + policyLookupSuccessful, + deductibleValue: currentDeductible, + isNoComp: noCoverage ?? false, availableLineItems: [], selectedProvider: '', deductibleText: 'Your deductible is', @@ -219,83 +229,84 @@ export default { rules: { selectionRequired: globalRules.OPTION_REQUIRED }, - supportingItems: null + supportingItems: null, + widget: { + subheader: 'SiteSubHeaderWidget', + verifiedItacAlert: 'VerifiedITACAlert', + explanatoryText: 'ExplanatoryTextWidget', + nextStep: 'NextStepsWidget', + serviceProviderQuestion: 'ServiceProviderQuestion' + } }; }, computed: { - verifiedITACAlertHeader() { - return this.getCmsContent( - 'VerifiedITACAlert', - 'HeadlineText' + coverageStatementSubHeader() { + return this.getTextFromCmsWithCustomIfStatements( + this.widget.subheader, + widgetFields.SUB_HEADER_WIDGET.SUB_HEADER_TEXT ); }, - verifiedITACAlertBody() { + verifiedItacAlertHeader() { return this.getCmsContent( - 'VerifiedITACAlert', - 'BodyText' + this.widget.verifiedItacAlert, + widgetFields.ALERT_WIDGET.HEADLINE_TEXT + ); + }, + verifiedItacAlertBody() { + return this.getCmsContent( + this.widget.verifiedItacAlert, + widgetFields.ALERT_WIDGET.BODY_TEXT )?.replaceAll('{custom:costSavings}', this.costSavings); }, - coverageStatementSubHeader() { - return this.getSubheaderTextFromCms('SiteSubHeaderWidget'); - }, secondaryText() { - return this.getSecondaryTextFromCms('SiteSubHeaderWidget'); + return this.getTextFromCmsWithCustomIfStatements( + this.widget.subheader, + widgetFields.CONTENT_GROUP_WIDGET.SECONDARY_TEXT + ); }, explanatoryText() { - return this.getExplantoryTextFromCms('ExplanatoryTextWidget'); + return this.getTextFromCmsWithCustomIfStatements( + this.widget.explanatoryText, + widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT + ); }, nextStepsHeader() { - return this.getHeaderTextFromCms('NextStepsWidget'); + return this.getTextFromCmsWithCustomIfStatements( + this.widget.nextStep, + widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT + ); }, nextStepsBody() { - return this.getBodyTextFromCms('NextStepsWidget')?.replaceAll('{custom:damage}', this.damageText); - }, - continueWithSchedulingBodyText() { - return this.getCmsContent('continueWithSchedulingCopy', 'BodyText'); - }, - unverifiedADASNextStepsBodyText() { - return this.getCmsContent('UnverifiedADASNextStepsWidget', 'BodyText')?.replaceAll('{custom:damage}', this.damageText); - }, - unverifiedNonADASNextStepsBodyText() { - return this.getCmsContent('UnverifiedNonADASNextStepsWidget', 'BodyText')?.replaceAll('{custom:damage}', this.damageText); - }, - unverifiedNonADASRepairBodyText() { - return this.getCmsContent('UnverifiedNonADASRepairWidget', 'BodyText'); + return this.getTextFromCmsWithCustomIfStatements( + this.widget.nextStep, + widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT + )?.replaceAll('{custom:damage}', this.damageText); }, damageText() { const damageString = getDamageString(); return damageString === 'match' ? '' : damageString; }, - vehicleDeductible() { - const deductible = useMainStore().order.currentDeductible; - return deductible; - }, formattedDeductible() { - return this.getDeductibleString(this.vehicleDeductible); - }, - isDeductibleZero() { - return this.vehicleDeductible === 0; - }, - policyLookupSuccessful() { - return useMainStore().order.policy.policyLookupSuccessful; + return this.getDeductibleString(this.deductibleValue); }, registerClaimSuccessful() { return useMainStore().payment.insuranceCoverage.isVerified; }, verifiedNoComp() { - return this.policyLookupSuccessful ? useMainStore().order.policy.noCoverage : false; + return this.policyLookupSuccessful && this.isNoComp; }, verifiedITAC() { return this.policyLookupSuccessful - && !this.verifiedNoComp - && this.vehicleDeductible > this.totalServicePrice; + && !this.isNoComp + && this.deductibleValue > this.totalServicePrice; }, + // TODO maybe tweak coveredAndServicePriceAboveOrEqualDeductible() { - return !this.verifiedNoComp && this.totalServicePrice >= this.vehicleDeductible; + return !this.verifiedNoComp && this.totalServicePrice >= this.deductibleValue; }, verifiedDeductible() { return useMainStore().isClaimRegistrationRequired - ? this.registerClaimSuccessful && this.coveredAndServicePriceAboveOrEqualDeductible && this.vehicleDeductible !== null + ? this.registerClaimSuccessful && this.coveredAndServicePriceAboveOrEqualDeductible && this.deductibleValue !== null : this.policyLookupSuccessful && this.coveredAndServicePriceAboveOrEqualDeductible; }, unverified() { @@ -305,9 +316,7 @@ export default { const parts = useMainStore().order.lineItems.glassParts; return parts !== null && !!parts.find((part) => part.requiresRecalibration); }, - isRepair() { - return useMainStore().order.damage.isRepair; - }, + // TODO replace with better method totalServicePrice() { let total = 0; this.availableLineItems.forEach((lineItem) => { @@ -319,27 +328,30 @@ export default { return this.getServicePriceString(this.totalServicePrice); }, costSavings() { - const savings = this.getITACCostSavings(this.vehicleDeductible, this.totalServicePrice); + const savings = this.getITACCostSavings(this.deductibleValue, this.totalServicePrice); const formattedSavings = parseFloat(savings).toFixed(2); return `$${formattedSavings}`; }, - questionText() { - return this.getCmsContent('ServiceProviderQuestion', 'QuestionText'); + serviceProviderQuestionText() { + return this.getCmsContent( + this.widget.serviceProviderQuestion, + widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT + ); }, - answersFromCms() { - return this.getCmsContent('ServiceProviderQuestion', 'Answers'); + serviceProviderQuestionAnswers() { + return this.getCmsContent( + this.widget.serviceProviderQuestion, + widgetFields.INPUT_QUESTION_WIDGET.ANSWERS + ); }, - displayQuote() { + isQuoteDisplayed() { return this.verifiedITAC || this.verifiedNoComp; } }, watch: { selectedProvider() { - if (this.selectedProvider === 'Safelite') { - this.$refs.siteFooter.updateButtonText('Continue with Safelite'); - } else { - this.$refs.siteFooter.updateButtonText('Continue'); - } + const buttonText = this.selectedProvider === SAFELITE_PROVIDER ? 'Continue with Safelite' : 'Safelite'; + this.$refs.siteFooter.updateButtonText(buttonText); }, nextStepsBody(newValue, oldValue) { if (newValue !== oldValue) { @@ -366,9 +378,6 @@ export default { } this.$refs.loadingModal.hideModal(); }, - async forwardButtonAction() { - return this.navigateForward(); - }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { useMainStore().saveSupportingItems(this.supportingItems); @@ -379,8 +388,8 @@ export default { { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else if (this.verifiedITAC || this.verifiedNoComp) { - useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); - if (this.selectedProvider === 'Safelite') { + useMainStore().updateIsSafeliteProvider(this.selectedProvider === SAFELITE_PROVIDER); + if (this.selectedProvider === SAFELITE_PROVIDER) { useMainStore().saveSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, @@ -407,25 +416,9 @@ export default { ); } }, - getHeaderTextFromCms(cmsWidgetName) { - const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); - return processIfStatements(header, 'custom', this.getCustomValueFromString); - }, - getSubheaderTextFromCms(cmsWidgetName) { - const subHeader = this.getCmsContent(cmsWidgetName, 'SubHeaderText'); - return processIfStatements(subHeader, 'custom', this.getCustomValueFromString); - }, - getBodyTextFromCms(cmsWidgetName) { - const bodyText = this.getCmsContent(cmsWidgetName, 'BodyText'); - return processIfStatements(bodyText, 'custom', this.getCustomValueFromString); - }, - getSecondaryTextFromCms(cmsWidgetName) { - const secondaryText = this.getCmsContent(cmsWidgetName, 'SecondaryText'); - return processIfStatements(secondaryText, 'custom', this.getCustomValueFromString); - }, - getExplantoryTextFromCms(cmsWidgetName) { - const explanatoryText = this.getCmsContent(cmsWidgetName, 'BodyText'); - return processIfStatements(explanatoryText, 'custom', this.getCustomValueFromString); + getTextFromCmsWithCustomIfStatements(widgetName, widgetField) { + const rawText = this.getCmsContent(widgetName, widgetField); + return processIfStatements(rawText, 'custom', this.getCustomValueFromString); }, getCustomValueFromString(str) { switch (str) { @@ -444,20 +437,23 @@ export default { case 'nonADASRepair': return this.isRepair; case 'deductibleOverZero': - return this.verifiedDeductible && !this.isDeductibleZero; // TODO what if deductible is negative? + return this.verifiedDeductible && this.deductibleValue !== 0; // TODO what if deductible is negative? case 'isDeductibleZero': - return this.verifiedDeductible && this.isDeductibleZero; + return this.verifiedDeductible && this.deductibleValue === 0; default: return null; } }, + // TODO move to common location getTotalLineItemPrice(lineItem) { return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; }, + // TODO use price formatter getDeductibleString(deductible) { const formattedDeductibleFloat = parseFloat(deductible).toFixed(2); return `$${formattedDeductibleFloat}`; }, + // TODO use price formatter getServicePriceString(price) { const formattedPriceFloat = parseFloat(price).toFixed(2); return `$${formattedPriceFloat}`; @@ -467,6 +463,9 @@ export default { }, setSupportingItems(newSupportingItems) { this.supportingItems = newSupportingItems; + }, + setAvailableLineItems(newAvailableLineItems) { + this.availableLineItems = newAvailableLineItems; } } }; diff --git a/src/store/index.js b/src/store/index.js index 114b9989..c2517558 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -947,10 +947,9 @@ export const useMainStore = defineStore({ }, async getSupportingItems() { - const glassPartsArray = this.order.lineItems.glassParts ?? []; - const { carId } = this.order.vehicle; - const { isRepair } = this.order.damage; - const { numberOfChips } = this.order.damage; + const glassPartsArray = this.lineItems.glassParts ?? []; + const { carId } = this.vehicle; + const { isRepair, numberOfChips } = this.damage; return globalMethods .callHttpClient({ From 715490f12f4d0033e508e348a4197031fc8f8053 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 13:39:43 -0500 Subject: [PATCH 588/674] Modifying supporting items --- src/store/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index c2517558..3ae011f1 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -950,6 +950,7 @@ export const useMainStore = defineStore({ const glassPartsArray = this.lineItems.glassParts ?? []; const { carId } = this.vehicle; const { isRepair, numberOfChips } = this.damage; + const { parentAccountNumber } = this.issConfig; return globalMethods .callHttpClient({ @@ -958,7 +959,7 @@ export const useMainStore = defineStore({ payload: { carId, damageType: isRepair ? 'Repair' : 'Replace', - parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, + parentAccountNumber, parts: glassPartsArray, numberOfRepairChips: isRepair ? numberOfChips : 0 } From 7a8c685cecd9b15ac0e224734b68de6073b154ae Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 13:42:37 -0500 Subject: [PATCH 589/674] Adding comment --- src/store/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/store/index.js b/src/store/index.js index 114b9989..8c32d3e9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -144,6 +144,7 @@ const getDefaultState = () => ({ lineItems: { glassParts: null, otherParts: null, + // TODO figure out when this needs set and reset, then just reference supportingItems: null, vaps: null }, From 881a79c7eb9e3920400258038d88eda971beffce Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:08:51 -0500 Subject: [PATCH 590/674] Cleaning up supportingItems setting --- .../coverage-statement/coverage-statement.vue | 5 +- src/layouts/schedule-page/schedule-page.vue | 43 ++------------ .../service-packages/service-packages.vue | 24 ++++++-- src/layouts/vehicle-damage/vehicle-damage.vue | 3 +- src/store/index.js | 56 +++++++------------ 5 files changed, 49 insertions(+), 82 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index f5ab548d..b9877b44 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -369,7 +369,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { - this.mainStore.saveSupportingItems(this.supportingItems); + this.mainStore.updateSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -379,7 +379,8 @@ export default { } else if (this.verifiedITAC || this.verifiedNoComp) { useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); if (this.selectedProvider === 'Safelite') { - this.mainStore.saveSupportingItems(this.supportingItems); + // TODO maybe don't save supporting items on this page + this.mainStore.updateSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route, diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index 5a3fb0d4..13a8315e 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -268,7 +268,9 @@ export default { return { mainStore }; }, data() { + const { supportingItems } = useMainStore().lineItems; return { + supportingItems, selectedDate: this.getSelectedDate(), selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(), selectableDatesData: [], @@ -324,7 +326,7 @@ export default { && ((serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE || serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) || serviceLocation.provider.providerNumber); - const supportingItems = useMainStore().lineItems.supportingItems !== null; + const supportingItems = this.supportingItems !== null; const damageInfo = useMainStore().order.damage.isRepair || (useMainStore().order.lineItems?.glassParts != null @@ -360,9 +362,8 @@ export default { return this.mainStore.order.schedule.date; }, getSelectedTimeSlotInfo() { - const supportingItems = this.getSupportingItems(); const isPremiumAppointment = - !!supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) + !!this.supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) .length > 0; const selectedTimeSlotInfo = { @@ -372,9 +373,6 @@ export default { return selectedTimeSlotInfo; }, - getSupportingItems() { - return this.mainStore.lineItems.supportingItems; - }, timeSlotModalClosed() { // Clear the selectedDate if no timeSlot has been selected if (this.selectedTimeSlotInfo.timeSlot.routeCode == null) { @@ -424,40 +422,7 @@ export default { } return `${hours}:${minutes} ${meridianNotation}`; }, - updateSupportingItems() { - const supportingItems = this.getSupportingItems(); - - // if we have a premium fee(early bird), then save/update supporting items - if ( - this.appointmentType === AppointmentTypeStrings.MOBILE - && this.selectedTimeSlotInfo?.isPremiumAppointment - ) { - const premiumFeeIndex = supportingItems.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE); - - if (premiumFeeIndex >= 0) { - supportingItems[premiumFeeIndex].laborAmount = - this.mobilePremiumAppointmentFee.laborAmount; - supportingItems[premiumFeeIndex].sellingPrice = - this.mobilePremiumAppointmentFee.sellingPrice; - supportingItems[premiumFeeIndex].kitPrice = - this.mobilePremiumAppointmentFee.kitPrice; - } else { - supportingItems.push(this.mobilePremiumAppointmentFee); - } - - this.mainStore.saveSupportingItemsSuppressingStateResetting(supportingItems); - } else { - // if it's not a mobile and/or premium early bird, then make sure we remove any that may have been added - const removePremiumFeeIndex = supportingItems.findIndex((item) => item.partType === PREMIUM_FEE_PART_TYPE); - - if (removePremiumFeeIndex >= 0) { - supportingItems.splice(removePremiumFeeIndex, 1); - this.mainStore.saveSupportingItemsSuppressingStateResetting(supportingItems); - } - } - }, forwardButtonAction() { - this.updateSupportingItems(); this.mainStore.saveSchedule(this.selectedTimeSlotInfo.timeSlot); this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route); diff --git a/src/layouts/service-packages/service-packages.vue b/src/layouts/service-packages/service-packages.vue index 8644ad85..8226c8a4 100644 --- a/src/layouts/service-packages/service-packages.vue +++ b/src/layouts/service-packages/service-packages.vue @@ -90,6 +90,7 @@ export default { const wipersPromise = await store.getWipers(); const rainDefensePromise = await store.getRainDefense(); + // TODO does this call need to happen here? const supportingItemsPromise = await store.getSupportingItems(); const promiseResultMap = [ { @@ -124,7 +125,13 @@ export default { let hasBailedOut = false; const pricingResults = await store.getPriceOrderItems(availableLineItems) .catch((err) => { - useMainStore().setBailout(to, bailoutMessage.pricingResponseError(availableLineItems.map((li) => li.partNumber), { code: err.code, message: err.message, data: err.data })); + useMainStore().setBailout( + to, + bailoutMessage.pricingResponseError( + availableLineItems.map((li) => li.partNumber), + { code: err.code, message: err.message, data: err.data } + ) + ); hasBailedOut = true; next(`/?issPage=${issPageValues.BAILOUT_PAGE}`); }); @@ -179,15 +186,22 @@ export default { this.selectedVaps = vapsItemsSelected; }, forwardButtonAction() { - const parts = { glassParts: this.pricedGlassParts, supportingItems: this.supportingItems, vaps: this.selectedVaps }; + const parts = { + glassParts: this.pricedGlassParts, + supportingItems: this.supportingItems, + vaps: this.selectedVaps + }; if (!allGlassPartsAndItemsHavePrices(parts)) { window.console.error('One or more items have no price assigned!'); } if (this.pricedGlassParts.length > 0) { - store.saveGlassParts(this.pricedGlassParts); + // TODO saving glass parts here + store.updateGlassParts(this.pricedGlassParts); } - store.saveSupportingItems(this.supportingItems); - store.saveVaps(this.selectedVaps); + // TODO saving supporting items on service packages page + // TODO does the glass parts array change? + store.updateSupportingItems(this.supportingItems); + store.updateVaps(this.selectedVaps); this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route); } diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index dd78afc0..892ec962 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -360,8 +360,9 @@ export default { ); if (this.isWindshieldRepair) { + // TODO only save supporting items on vehicle damage page if windshield repair const supportingItems = await useMainStore().getSupportingItems(); - this.mainStore.saveSupportingItems(supportingItems.data); + useMainStore().updateSupportingItems(supportingItems.data); } if (this.mainStore.damage.isRepair) { diff --git a/src/store/index.js b/src/store/index.js index 8c32d3e9..3954b24b 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -947,11 +947,12 @@ export const useMainStore = defineStore({ }); }, + // TODO this needs called when vehicle, damage, or glass parts changes async getSupportingItems() { - const glassPartsArray = this.order.lineItems.glassParts ?? []; - const { carId } = this.order.vehicle; - const { isRepair } = this.order.damage; - const { numberOfChips } = this.order.damage; + const { glassParts } = this.lineItems; + const { carId } = this.vehicle; + const { isRepair, numberOfChips } = this.damage; + const { parentAccountNumber } = this.issConfig; return globalMethods .callHttpClient({ @@ -960,8 +961,8 @@ export const useMainStore = defineStore({ payload: { carId, damageType: isRepair ? 'Repair' : 'Replace', - parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, - parts: glassPartsArray, + parentAccountNumber, + parts: glassParts ?? [], numberOfRepairChips: isRepair ? numberOfChips : 0 } }); @@ -1434,8 +1435,9 @@ export const useMainStore = defineStore({ this.order.payment.insuranceCoverage.isVerified = false; }, + // Note that this is only used in the store updateSupportingItems(partsData) { - this.order.lineItems.supportingItems = partsData; + this.lineItems.supportingItems = partsData; }, updateVaps(partsData) { @@ -1473,8 +1475,8 @@ export const useMainStore = defineStore({ this.order.originalDeductible = vehicle.deductible; this.order.currentDeductible = vehicle.deductible; - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateSupportingItems(null); + this.updateVaps(null); }, updateVehicleVin(vin) { @@ -1497,6 +1499,7 @@ export const useMainStore = defineStore({ resetGlassPartsState() { this.order.lineItems.glassParts = null; + this.order.lineItems.supportingItems = null; this.order.damage.partQuestionAnswers = null; this.order.damage.moldingQuestionAnswers = null; this.order.damage.capabilityQuestionAnswers = null; @@ -1505,6 +1508,7 @@ export const useMainStore = defineStore({ this.applicationUser.pageData[issPageValues.MOLDING_QUESTIONS] = null; this.applicationUser.pageData[issPageValues.CAPABILITY_QUESTIONS] = null; }, + // TODO when schedule reset, supporting items modified resetSchedule() { this.order.schedule.date = null; this.order.schedule.startTime = null; @@ -1522,12 +1526,6 @@ export const useMainStore = defineStore({ 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; @@ -1686,8 +1684,8 @@ export const useMainStore = defineStore({ this.updateGlassParts(null); this.updateMoldingQuestionAnswers(null); this.updateCapabilityQuestionAnswers(null); - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateSupportingItems(null); + this.updateVaps(null); this.updatePageData({ page: issPageValues.VEHICLE_PARTS, data: null }); this.updatePageData({ page: issPageValues.MOLDING_QUESTIONS, data: null }); @@ -1731,18 +1729,6 @@ export const useMainStore = defineStore({ // 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) { @@ -2044,6 +2030,7 @@ export const useMainStore = defineStore({ if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); + // TODO probably reset supporting items } // Save new values @@ -2062,6 +2049,7 @@ export const useMainStore = defineStore({ if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); + // TODO probably reset supporting items } // Save new values @@ -2078,6 +2066,7 @@ export const useMainStore = defineStore({ // Dependencies already cleared in above statement this.resetDamageState(); this.resetGlassPartsState(); + // TODO reset supporting items state } // Save new values @@ -2111,21 +2100,18 @@ export const useMainStore = defineStore({ resetRegistrationAndDependencies() { this.resetRegistrationState(); this.resetGlassPartsState(); - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateVaps(null); }, resetDamageAndDependencies() { this.resetDamageState(); this.resetGlassPartsState(); - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateVaps(null); }, resetPartsAndDependencies() { this.resetGlassPartsState(); - this.resetSupportingItemsState(); - this.resetVapsState(); + this.updateVaps(null); this.resetServiceLocationAndDependencies(); }, From c8b491cbbd3eb808e448aea9fa28dae4c9ae31f7 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:10:23 -0500 Subject: [PATCH 591/674] Removing comment --- src/layouts/coverage-statement/coverage-statement.vue | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index b9877b44..7338f1ad 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -369,7 +369,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { - this.mainStore.updateSupportingItems(this.supportingItems); + useMainStore().updateSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -379,8 +379,7 @@ export default { } else if (this.verifiedITAC || this.verifiedNoComp) { useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); if (this.selectedProvider === 'Safelite') { - // TODO maybe don't save supporting items on this page - this.mainStore.updateSupportingItems(this.supportingItems); + useMainStore().updateSupportingItems(this.supportingItems); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route, From de406b6fbbb688fc5a3ad4372199b6f15a5d702d Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:12:22 -0500 Subject: [PATCH 592/674] Removing comment --- src/layouts/service-packages/service-packages.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/service-packages/service-packages.vue b/src/layouts/service-packages/service-packages.vue index 8226c8a4..52fc9ba1 100644 --- a/src/layouts/service-packages/service-packages.vue +++ b/src/layouts/service-packages/service-packages.vue @@ -90,7 +90,6 @@ export default { const wipersPromise = await store.getWipers(); const rainDefensePromise = await store.getRainDefense(); - // TODO does this call need to happen here? const supportingItemsPromise = await store.getSupportingItems(); const promiseResultMap = [ { From e359126d3dd02f536eace2b355262300d48f6c74 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:14:17 -0500 Subject: [PATCH 593/674] Removing comment --- src/layouts/service-packages/service-packages.vue | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/layouts/service-packages/service-packages.vue b/src/layouts/service-packages/service-packages.vue index 52fc9ba1..ea1cb229 100644 --- a/src/layouts/service-packages/service-packages.vue +++ b/src/layouts/service-packages/service-packages.vue @@ -194,11 +194,8 @@ export default { window.console.error('One or more items have no price assigned!'); } if (this.pricedGlassParts.length > 0) { - // TODO saving glass parts here store.updateGlassParts(this.pricedGlassParts); } - // TODO saving supporting items on service packages page - // TODO does the glass parts array change? store.updateSupportingItems(this.supportingItems); store.updateVaps(this.selectedVaps); From 63872cd9000c187ef1b67c71ac081f293c2d88ec Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:15:15 -0500 Subject: [PATCH 594/674] Removing comment --- src/layouts/vehicle-damage/vehicle-damage.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue index 892ec962..2771b30e 100644 --- a/src/layouts/vehicle-damage/vehicle-damage.vue +++ b/src/layouts/vehicle-damage/vehicle-damage.vue @@ -360,7 +360,6 @@ export default { ); if (this.isWindshieldRepair) { - // TODO only save supporting items on vehicle damage page if windshield repair const supportingItems = await useMainStore().getSupportingItems(); useMainStore().updateSupportingItems(supportingItems.data); } From 3a75fe9658a7537fd3b1c5dddd6f21a61e7cb74d Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:16:07 -0500 Subject: [PATCH 595/674] Removing comment --- src/store/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 3954b24b..be6c7343 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -144,7 +144,6 @@ const getDefaultState = () => ({ lineItems: { glassParts: null, otherParts: null, - // TODO figure out when this needs set and reset, then just reference supportingItems: null, vaps: null }, From 60012cb033681ab4f410115f19211af9eccb4392 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:16:45 -0500 Subject: [PATCH 596/674] Removing comment --- src/store/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index be6c7343..49027c3c 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -946,7 +946,6 @@ export const useMainStore = defineStore({ }); }, - // TODO this needs called when vehicle, damage, or glass parts changes async getSupportingItems() { const { glassParts } = this.lineItems; const { carId } = this.vehicle; From c7ffb35e4c672ea7bfac62ae6a07ab6b2f687164 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:17:24 -0500 Subject: [PATCH 597/674] Removing comment --- src/store/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 49027c3c..098b7f84 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1433,9 +1433,8 @@ export const useMainStore = defineStore({ this.order.payment.insuranceCoverage.isVerified = false; }, - // Note that this is only used in the store updateSupportingItems(partsData) { - this.lineItems.supportingItems = partsData; + this.order.lineItems.supportingItems = partsData; }, updateVaps(partsData) { From e5709444f9c5745b03334dac9c20371141b67fd9 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:19:36 -0500 Subject: [PATCH 598/674] Removing comment --- src/store/index.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 098b7f84..3aad08dc 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1505,7 +1505,6 @@ export const useMainStore = defineStore({ this.applicationUser.pageData[issPageValues.MOLDING_QUESTIONS] = null; this.applicationUser.pageData[issPageValues.CAPABILITY_QUESTIONS] = null; }, - // TODO when schedule reset, supporting items modified resetSchedule() { this.order.schedule.date = null; this.order.schedule.startTime = null; @@ -1513,15 +1512,6 @@ export const useMainStore = defineStore({ 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; - } }, resetDamageState() { this.order.damage.isRepair = null; @@ -2027,7 +2017,6 @@ export const useMainStore = defineStore({ if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); - // TODO probably reset supporting items } // Save new values @@ -2046,7 +2035,6 @@ export const useMainStore = defineStore({ if (!isSelectedGlassAvailableForVehicle) { this.resetDamageState(); this.resetGlassPartsState(); - // TODO probably reset supporting items } // Save new values From 21d811c815343761f10cba1405ba59d32aa03c92 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:20:12 -0500 Subject: [PATCH 599/674] Removing comment --- src/store/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 3aad08dc..3ba028ec 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2051,7 +2051,6 @@ export const useMainStore = defineStore({ // Dependencies already cleared in above statement this.resetDamageState(); this.resetGlassPartsState(); - // TODO reset supporting items state } // Save new values From 9ddc157ed3616d69e273dc409dbb11805b87527a Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 4 Mar 2024 15:38:08 -0500 Subject: [PATCH 600/674] display service duration --- .../order-confirmation/order-confirmation.vue | 94 +++++++++++++++---- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 38f2dc9e..775630ef 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -29,6 +29,10 @@ class="appointment-text text-center text-color--black lh-base" v-html="appointmentWordingText">
    +
    +
    ${this.providerAddress},
    ${this.providerCity}, ${this.providerState} ${this.providerZipCode}
    `; }, appointmentWordingText() { - return this.formatWordingText(this.appointmentType); + switch (this.appointmentType) { + case 'MOBILE': + return this.mobileWordingText?.replaceAll( + '{custom:address}', + this.serviceLocationFullAddress + ); + case 'DROP OFF': + return this.dropOffAndInShopWordingText?.replaceAll( + '{custom:address}', + this.providerFullAddress + ); + case 'INSHOP': + return this.dropOffAndInShopWordingText?.replaceAll( + '{custom:address}', + this.providerFullAddress + ); + default: + return null; + } + }, + appointmentWordingText2() { + switch (this.appointmentType) { + case 'MOBILE': + return this.mobileWordingText2; + case 'DROP OFF': + return this.dropOffAndInShopWordingText2; + case 'INSHOP': + return this.dropOffAndInShopWordingText2?.replaceAll( + '{custom:inShopDuration}', + this.inShopAppointmentDuration + ); + default: + return null; + } + }, + mobileAppointment() { + return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'MOBILE'; + }, + inShopAppointment() { + return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'INSHOP'; + }, + dropOffAppointment() { + return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'DROP OFF'; + }, + inShopAppointmentDuration() { + const inshopDurationTime = getDisplayTextForDurationLength( + this.mainStore.order.schedule.jobMinMinutes, + this.mainStore.order.schedule.jobMaxMinutes + ); + return inshopDurationTime; } }, mounted() { @@ -192,23 +252,17 @@ export default { return null; } }, - formatWordingText(appointmentType) { - switch (appointmentType) { - case 'MOBILE': - return this.mobileWordingText?.replaceAll( - '{custom:address}', - this.serviceLocationFullAddress - ); - case 'DROP OFF': - return this.dropOffAndInShopWordingText?.replaceAll( - '{custom:address}', - this.providerFullAddress - ); - case 'INSHOP': - return this.dropOffAndInShopWordingText?.replaceAll( - '{custom:address}', - this.providerFullAddress - ); + processIfStatements, + getBodyText2FromCms(cmsWidgetName) { + const body2Text = this.getCmsContent(cmsWidgetName, 'BodyText2'); + return this.processIfStatements(body2Text, 'custom', this.getCustomValueFromString); + }, + getCustomValueFromString(str) { + switch (str) { + case 'inShopAppointment': + return this.inShopAppointment; + case 'dropOffAppointment': + return this.dropOffAppointment; default: return null; } From 7651441115e2f08cd49e8eee4accb4dc7eb027af Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Mon, 4 Mar 2024 15:42:00 -0500 Subject: [PATCH 601/674] style fix --- src/layouts/order-confirmation/order-confirmation.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 775630ef..4b299b07 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -26,11 +26,11 @@

    {{ appointmentTimeFormatted }}

    @@ -308,6 +308,7 @@ $page-side-padding: 1.5rem; .appointment-text { :deep(strong) { font-weight: $font-weight-bold; + color: $black; } } From 24103335eec282fad8ded09087cf8502b0150ad6 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Mon, 4 Mar 2024 15:46:31 -0500 Subject: [PATCH 602/674] Fixing tests --- .../schedule-page/schedule-page.spec.js | 79 ------------------- src/layouts/schedule-page/schedule-page.vue | 7 +- 2 files changed, 4 insertions(+), 82 deletions(-) diff --git a/src/layouts/schedule-page/schedule-page.spec.js b/src/layouts/schedule-page/schedule-page.spec.js index bc0d80df..c025ece6 100644 --- a/src/layouts/schedule-page/schedule-page.spec.js +++ b/src/layouts/schedule-page/schedule-page.spec.js @@ -75,8 +75,6 @@ function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) { } }); - // mountOptions.global.mocks["$store"] = store; - mountOptions.global.stubs = { siteFooter: footerStub, loadingModal: loadingModalStub @@ -337,81 +335,4 @@ describe('schedule-page.vue', () => { // Assert expect(wrapper.vm.$router.navigate).toHaveBeenCalled(); }); - test('for mobile appts, updateSupportingItems should call store action to save supporting items', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE; - wrapper.vm.mobilePremiumAppointmentFee = 14.99; - wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = true; - wrapper.vm.mainStore.lineItems.supportingItems = [ - { - partNumber: 'EARLY BIRD', - description: null, - partType: 'EARLY BIRD', - laborAmount: 0, - sellingPrice: 0, - kitPrice: 0 - } - ]; - const store = useMainStore(); - - // Act - await wrapper.vm.updateSupportingItems(); - - // Assert - expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(1); - expect(wrapper.vm.mainStore.lineItems.supportingItems) - .toEqual(expect.arrayContaining([ - expect.objectContaining({ - partType: 'EARLY BIRD' - }) - ])); - }); - test( - 'for Inshop appts, updateSupportingItems should call store action to save supporting items WITHOUT the EARLY BIRD supporting item', - async () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP; - wrapper.vm.mobilePremiumAppointmentFee = 14.99; - wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = true; - wrapper.vm.mainStore.lineItems.supportingItems = [ - { - partNumber: 'EARLY BIRD', - description: null, - partType: 'EARLY BIRD', - laborAmount: 0, - sellingPrice: 0, - kitPrice: 0 - } - ]; - const store = useMainStore(); - - // Act - await wrapper.vm.updateSupportingItems(); - - // Assert - expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(1); - expect(wrapper.vm.mainStore.lineItems.supportingItems) - .not.toEqual(expect.arrayContaining([ - expect.objectContaining({ - partType: 'EARLY BIRD' - }) - ])); - } - ); - test('if no EARLY BIRD supporting item, then updateSupportingItems should NOT call store action', async () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.mainStore.order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE; - wrapper.vm.mobilePremiumAppointmentFee = 14.99; - wrapper.vm.selectedTimeSlotInfo.isPremiumAppointment = false; - wrapper.vm.mainStore.lineItems.supportingItems = []; - const store = useMainStore(); - // Act - await wrapper.vm.updateSupportingItems(); - - // Assert - expect(store.saveSupportingItemsSuppressingStateResetting).toHaveBeenCalledTimes(0); - }); }); diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index 13a8315e..4636b834 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -268,9 +268,7 @@ export default { return { mainStore }; }, data() { - const { supportingItems } = useMainStore().lineItems; return { - supportingItems, selectedDate: this.getSelectedDate(), selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(), selectableDatesData: [], @@ -293,6 +291,9 @@ export default { } return this.selectableDatesData.days?.find((selectableDate) => selectableDate.date === this.selectedDate); + }, + supportingItems() { + return useMainStore().lineItems.supportingItems; } }, watch: { @@ -363,7 +364,7 @@ export default { }, getSelectedTimeSlotInfo() { const isPremiumAppointment = - !!this.supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) + !!(this.supportingItems?.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) ?? []) .length > 0; const selectedTimeSlotInfo = { From 4e4f99f7c90d4e583cd47fb107e44225ebbca8b5 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Tue, 5 Mar 2024 10:05:55 -0500 Subject: [PATCH 603/674] Moving line item pricing to price calculator --- src/helpers/price-calculator.js | 10 ++ src/helpers/price-calculator.spec.js | 56 +++++++++++ .../coverage-statement/coverage-statement.vue | 92 +++++++------------ 3 files changed, 99 insertions(+), 59 deletions(-) create mode 100644 src/helpers/price-calculator.js create mode 100644 src/helpers/price-calculator.spec.js diff --git a/src/helpers/price-calculator.js b/src/helpers/price-calculator.js new file mode 100644 index 00000000..9e69259b --- /dev/null +++ b/src/helpers/price-calculator.js @@ -0,0 +1,10 @@ +function getPriceOfLineItem(lineItem) { + return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; +} + +export default function getPriceOfLineItems(lineItems) { + return lineItems.reduce( + (accumulator, lineItem) => accumulator + getPriceOfLineItem(lineItem), + 0 + ); +} diff --git a/src/helpers/price-calculator.spec.js b/src/helpers/price-calculator.spec.js new file mode 100644 index 00000000..4d09128b --- /dev/null +++ b/src/helpers/price-calculator.spec.js @@ -0,0 +1,56 @@ +import getPriceOfLineItems from "@/helpers/price-calculator.js"; + +describe('getPriceOfLineItems', () => { + test('Returns zero when no line items', () => { + // Arrange + const lineItems = []; + + // Act + const result = getPriceOfLineItems(lineItems); + + // Assert + expect(result).toBe(0); + }); + test('Returns expected when one line item', () => { + // Arrange + const lineItems = [ + { + kitPrice: 1, + laborAmount: 2, + sellingPrice: 3 + } + ]; + const expected = 6; + + // Act + const result = getPriceOfLineItems(lineItems); + + // Assert + expect(result).toBe(expected); + }); + test('Returns expected when multiple line items', () => { + // Arrange + const lineItems = [ + { + kitPrice: 1, + laborAmount: 2, + sellingPrice: 3 + }, + { + kitPrice: 1 + }, + { + kitPrice: 10, + laborAmount: 100, + sellingPrice: 1000 + } + ]; + const expected = 1117; + + // Act + const result = getPriceOfLineItems(lineItems); + + // Assert + expect(result).toBe(expected); + }); +}); diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index b6ed7771..5ac78138 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -40,7 +40,7 @@
    - {{ formattedServicePrice }} + {{ servicePriceForDisplay }}
    this.totalServicePrice; }, - // TODO maybe tweak coveredAndServicePriceAboveOrEqualDeductible() { return !this.verifiedNoComp && this.totalServicePrice >= this.deductibleValue; }, @@ -316,21 +321,17 @@ export default { const parts = useMainStore().order.lineItems.glassParts; return parts !== null && !!parts.find((part) => part.requiresRecalibration); }, - // TODO replace with better method totalServicePrice() { - let total = 0; - this.availableLineItems.forEach((lineItem) => { - total += this.getTotalLineItemPrice(lineItem); - }); - return total; + return getPriceOfLineItems(this.baseServiceLineItems); }, - formattedServicePrice() { - return this.getServicePriceString(this.totalServicePrice); + servicePriceForDisplay() { + return this.getFormattedAmount(this.totalServicePrice); }, - costSavings() { - const savings = this.getITACCostSavings(this.deductibleValue, this.totalServicePrice); - const formattedSavings = parseFloat(savings).toFixed(2); - return `$${formattedSavings}`; + itacCostSavings() { + return this.deductibleValue - this.totalServicePrice; + }, + itacCostSavingsForDisplay() { + return this.getFormattedAmount(this.itacCostSavings); }, serviceProviderQuestionText() { return this.getCmsContent( @@ -367,10 +368,13 @@ export default { arePagePrerequisitesValid() { return !!useMainStore().vehicle.carId; }, + getFormattedAmount(amount) { + return this.currencyFormatter.format(amount); + }, async initializeComponent() { useMainStore().updatePolicyITACFlag(this.verifiedITAC); if (this.policyLookupSuccessful - && useMainStore().order.vehicle.policyVehicleId >= 0 + && useMainStore().vehicle.policyVehicleId >= 0 && useMainStore().isClaimRegistrationRequired && !useMainStore().isClaimAlreadyRegistered && (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC)) { @@ -380,11 +384,7 @@ export default { }, async navigateForward() { if (this.unverified || this.verifiedDeductible) { -<<<<<<< HEAD - useMainStore().saveSupportingItems(this.supportingItems); -======= useMainStore().updateSupportingItems(this.supportingItems); ->>>>>>> 24103335eec282fad8ded09087cf8502b0150ad6 this.$router.navigate( navigationScenarios.CLICKED_FORWARD, this.$route, @@ -392,37 +392,28 @@ export default { { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } ); } else if (this.verifiedITAC || this.verifiedNoComp) { -<<<<<<< HEAD useMainStore().updateIsSafeliteProvider(this.selectedProvider === SAFELITE_PROVIDER); if (this.selectedProvider === SAFELITE_PROVIDER) { - useMainStore().saveSupportingItems(this.supportingItems); -======= - useMainStore().updateIsSafeliteProvider(this.selectedProvider === 'Safelite'); - if (this.selectedProvider === 'Safelite') { useMainStore().updateSupportingItems(this.supportingItems); ->>>>>>> 24103335eec282fad8ded09087cf8502b0150ad6 this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, - this.$route, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + this.$route ); } else { useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, - this.$route, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + this.$route ); } } else { - useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.coverageStatementInvalidState()); + useMainStore().setBailout( + this.$router.currentRoute, + bailoutMessage.coverageStatementInvalidState() + ); this.$router.navigate( navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE, - this.$route, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } + this.$route ); } }, @@ -454,28 +445,11 @@ export default { return null; } }, - // TODO move to common location - getTotalLineItemPrice(lineItem) { - return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; - }, - // TODO use price formatter - getDeductibleString(deductible) { - const formattedDeductibleFloat = parseFloat(deductible).toFixed(2); - return `$${formattedDeductibleFloat}`; - }, - // TODO use price formatter - getServicePriceString(price) { - const formattedPriceFloat = parseFloat(price).toFixed(2); - return `$${formattedPriceFloat}`; - }, - getITACCostSavings(vehicleDeductible, totalServicePrice) { - return vehicleDeductible - totalServicePrice; - }, setSupportingItems(newSupportingItems) { this.supportingItems = newSupportingItems; }, - setAvailableLineItems(newAvailableLineItems) { - this.availableLineItems = newAvailableLineItems; + setBaseServiceLineItems(lineItems) { + this.baseServiceLineItems = lineItems; } } }; @@ -485,7 +459,7 @@ export default { .cost { color: $green; font-size: 2rem; - font-weight: 300; + font-weight: $font-weight-light; line-height: 2.75rem; } From d5bf56418ac6a9fc8cc31d466c8ef03dff66d6e2 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Tue, 5 Mar 2024 10:40:12 -0500 Subject: [PATCH 604/674] Starting outline of tests --- src/helpers/price-calculator.js | 4 +- .../coverage-statement.spec.js | 54 +++++++++++++++++++ .../coverage-statement/coverage-statement.vue | 2 +- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/helpers/price-calculator.js b/src/helpers/price-calculator.js index 9e69259b..b44abc5a 100644 --- a/src/helpers/price-calculator.js +++ b/src/helpers/price-calculator.js @@ -1,5 +1,7 @@ function getPriceOfLineItem(lineItem) { - return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; + return (lineItem?.kitPrice ?? 0) + + (lineItem?.laborAmount ?? 0) + + (lineItem?.sellingPrice ?? 0); } export default function getPriceOfLineItems(lineItems) { diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index a597b7f9..79765a88 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -828,6 +828,60 @@ describe.skip('coverageStatement.vue', () => { }); describe('coverageStatement.vue-working', () => { + // test('initial data is as expected', () => {}); + describe('Rendering', () => { + test('Should render site header', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const siteHeader = wrapper.findComponent({ ref: 'siteHeader' }); + + // Assert + expect(siteHeader.exists()).toBe(true); + }); + test('Should render site subheader', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const subheader = wrapper.find({ ref: 'siteSubHeader' }); + + // Assert + expect(subheader.exists()).toBe(true); + }); + + test('Should render explanatory text', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const explanatoryText = wrapper.find({ ref: 'explanatoryText' }); + + // Assert + expect(explanatoryText.exists()).toBe(true); + }); + test('Should render secondary text', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const secondaryText = wrapper.find({ ref: 'secondaryText' }); + + // Assert + expect(secondaryText.exists()).toBe(true); + }); + test('Should render site footer', () => { + // Arrange + const { wrapper } = getMountedComponent({}); + + // Act + const footer = wrapper.findComponent({ ref: 'siteFooter' }); + + // Assert + expect(footer.exists()).toBe(true); + }); + }); describe('ITAC flag', () => { test('ITAC flag updated once component is initialized', async () => { // Arrange diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 5ac78138..8776ebe1 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -200,7 +200,7 @@ export default { vm.setCmsContent(resultMap.cmsContent); vm.setSupportingItems(resultMap.supportingItems); // eslint-disable-next-line no-param-reassign - vm.setAvailableLineItems(pricingResults); + vm.setBaseServiceLineItems(pricingResults); vm.$refs.loadingModal.showModal(); vm.initializeComponent(); if (!vm.unverified) { From 8e9302df405fa18d31160ebdcc422d97722cf0d1 Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Tue, 27 Feb 2024 16:46:34 -0500 Subject: [PATCH 605/674] SSR-1081 handling payment return info from hop --- src/constants/query-strings.js | 17 +- src/constants/web-storage-constants.js | 5 + src/helpers/querystring-helper.js | 11 ++ src/layouts/payment-page/payment-page.vue | 8 +- src/layouts/payment-return/payment-return.vue | 145 ++++++++++++++++++ .../router-constants/navigation-scenarios.js | 3 + src/router/router-constants/routing-table.js | 17 ++ src/store/index.js | 76 +++++++-- 8 files changed, 261 insertions(+), 21 deletions(-) create mode 100644 src/constants/web-storage-constants.js create mode 100644 src/helpers/querystring-helper.js create mode 100644 src/layouts/payment-return/payment-return.vue diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index 9b486517..f217dea4 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -1,5 +1,20 @@ const queryStrings = Object.freeze({ - ISS_PAGE: 'issPage' + ISS_PAGE: 'issPage', + ERROR: 'error', + SUBSCRIPTIONID: 'subscriptionid', + REFERRAL_SEQ_NUM: 'referralseqnum', + CARD_EXPIRATION_MONTH: 'card_expirationmonth', + CARD_EXPIRATION_YEAR: 'card_expirationyear', + CARD_TYPE: 'sgcardtype', + BILL_TO_POSTAL_CODE: 'billto_postalcode', + BILL_TO_FIRST_NAME: 'billto_firstname', + BILL_TO_LAST_NAME: 'billto_lastname', + REFERENCE_NUMBER: 'req_reference_number', + AUTH_CODE: 'auth_code', + TRANSACTION_ID: 'transaction_id', + TRANS_REFERENCE_NUMBER: 'auth_trans_ref_no', + LAST_FOUR: 'last_four', + DISPLAY_PAY_IN_ADVANCE_ALERT: 'displayPayInAdvanceAlert' }); export default queryStrings; diff --git a/src/constants/web-storage-constants.js b/src/constants/web-storage-constants.js new file mode 100644 index 00000000..29c814cf --- /dev/null +++ b/src/constants/web-storage-constants.js @@ -0,0 +1,5 @@ +const webStorageConstants = Object.freeze({ + SUBMITTED_ORDER: 'submittedOrder' +}); + +export default webStorageConstants; diff --git a/src/helpers/querystring-helper.js b/src/helpers/querystring-helper.js new file mode 100644 index 00000000..32900e96 --- /dev/null +++ b/src/helpers/querystring-helper.js @@ -0,0 +1,11 @@ +export default function getQuerystringParameter(key) { + const queryString = window.location.search; + const urlParams = new URLSearchParams(queryString); + const lowerCaseParams = new URLSearchParams(); + + urlParams.forEach((value, name) => { + lowerCaseParams.append(name.toLowerCase(), value); + }); + + return lowerCaseParams.get(key.toLowerCase()); +} diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index 7612e842..1f77de74 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -460,15 +460,11 @@ export default { computed: { payInAdvanceResponseUrl() { const { protocol, host } = window.location; - return `${protocol}//${host}/?issPage=${ - issPageValues.PAYMENT_RETURN - }&src=iss-nextgen`; + return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN}&src=iss-nextgen`; }, payInAdvanceCancelUrl() { const { protocol, host } = window.location; - return `${protocol}//${host}/?issPage=${ - issPageValues.PAYMENT_METHOD - }&src=iss-nextgen`; + return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_METHOD}&src=iss-nextgen`; }, dynamicCSSUrl() { const { protocol, hostname, port } = window.location; diff --git a/src/layouts/payment-return/payment-return.vue b/src/layouts/payment-return/payment-return.vue new file mode 100644 index 00000000..1ef57a4b --- /dev/null +++ b/src/layouts/payment-return/payment-return.vue @@ -0,0 +1,145 @@ + + + diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index 967b99d4..bd079640 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -96,6 +96,9 @@ const navigationScenarios = Object.freeze({ // Payment CLICKED_PAY_NOW: 'CLICKED_PAY_NOW', + PAY_IN_ADVANCE_ERROR: 'PAY_IN_ADVANCE_ERROR', + PAY_IN_ADVANCE_CREDIT_CARD_ERROR: 'PAY_IN_ADVANCE_CREDIT_CARD_ERROR', + PAY_IN_ADVANCE_SUCCESS: 'PAY_IN_ADVANCE_SUCCESS', // Bailout CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index d20f59cd..60d76dcd 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -641,6 +641,23 @@ const routingTable = () => [ } ] }, + { + issPageValue: issPageValues.PAYMENT_RETURN, + maps: [ + { + scenario: navigationScenarios.PAY_IN_ADVANCE_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_METHOD + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_CREDIT_CARD_ERROR, + destinationIssPageValue: issPageValues.PAYMENT_PAGE + }, + { + scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, + destinationIssPageValue: issPageValues.CONFIRMATION + }, + ] + }, { issPageValue: issPageValues.TPA_CONFIRMATION, maps: [ diff --git a/src/store/index.js b/src/store/index.js index 3ba028ec..cc1b2986 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -19,6 +19,7 @@ import { noCoverageForSelectedVehicle, repairWaivedForSelectedVehicle } from '@/helpers/policy-vehicle-helper'; +import webStorageConstants from '@/constants/web-storage-constants'; const storeId = 'main'; @@ -155,7 +156,21 @@ const getDefaultState = () => ({ }, parentAccountNumber: 0, isPayInAdvance: null, - payInAdvanceType: null + payInAdvanceType: null, + ccToken: { + subscriptionId: null, + expMonth: null, + expYear: null, + cardType: null, + billToPostalCode: null, + billToFirstName: null, + billToLastName: null, + referenceNumber: null, + authCode: null, + transactionId: null, + transReferenceNumber: null, + lastFour: null + } }, contactInfo: { firstName: null, @@ -934,18 +949,6 @@ export const useMainStore = defineStore({ }); }, - getCarrierAccountInfo() { - return new Promise((resolve, reject) => { - globalMethods.callHttpClient({ - method: endpoints.GetAccountInfo.method, - endpoint: endpoints.GetAccountInfo.url + this.issConfig.parentAccountNumber - }).then((response) => { - this.order.carrierPhoneNumber = response.data.phoneNumber; - return resolve(response.data); - }).catch((error) => reject(error)); - }); - }, - async getSupportingItems() { const { glassParts } = this.lineItems; const { carId } = this.vehicle; @@ -1383,6 +1386,10 @@ export const useMainStore = defineStore({ this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter; }, + resetState() { + Object.assign(this, getDefaultState()); + }, + resetRegistrationState() { this.order.vehicle.registration.licensePlate = null; this.order.vehicle.registration.address = null; @@ -2135,7 +2142,48 @@ export const useMainStore = defineStore({ method: endpoints.GetPaymentSignature.method, endpoint: endpoints.GetPaymentSignature.url }); - } + }, + + updateCCToken(ccToken) { + this.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; + this.order.payment.ccToken.expMonth = ccToken.expMonth; + this.order.payment.ccToken.expYear = ccToken.expYear; + this.order.payment.ccToken.cardType = ccToken.cardType; + this.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; + this.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; + this.order.payment.ccToken.billToLastName = ccToken.billToLastName; + this.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; + this.order.payment.ccToken.authCode = ccToken.authCode; + this.order.payment.ccToken.transactionId = ccToken.transactionId; + this.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; + this.order.payment.ccToken.lastFour = ccToken.lastFour; + }, + + hasSubmittedOrder() { + return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; + }, + + createSubmittedOrder() { + if (this.hasSubmittedOrder()) { + return; + } + const submittedOrder = this.order; + const { experiments } = this.applicationUser; + + // set to local storage + window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); + + // clear vuex + this.resetState(); + + // restore user's experiments + this.applicationUser.experiments = experiments; + }, + + resetSubmittedOrder() { + // clear from local storage + window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); + }, }, persist: true From 1a5b958b8c53309805079b319477024f53199303 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 4 Mar 2024 14:39:41 -0500 Subject: [PATCH 606/674] reorder alphabetically sans isspage --- src/constants/query-strings.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js index f217dea4..576d1e5b 100644 --- a/src/constants/query-strings.js +++ b/src/constants/query-strings.js @@ -1,20 +1,21 @@ const queryStrings = Object.freeze({ ISS_PAGE: 'issPage', - ERROR: 'error', - SUBSCRIPTIONID: 'subscriptionid', - REFERRAL_SEQ_NUM: 'referralseqnum', + AUTH_CODE: 'auth_code', + BILL_TO_FIRST_NAME: 'billto_firstname', + BILL_TO_LAST_NAME: 'billto_lastname', + BILL_TO_POSTAL_CODE: 'billto_postalcode', CARD_EXPIRATION_MONTH: 'card_expirationmonth', CARD_EXPIRATION_YEAR: 'card_expirationyear', CARD_TYPE: 'sgcardtype', - BILL_TO_POSTAL_CODE: 'billto_postalcode', - BILL_TO_FIRST_NAME: 'billto_firstname', - BILL_TO_LAST_NAME: 'billto_lastname', - REFERENCE_NUMBER: 'req_reference_number', - AUTH_CODE: 'auth_code', - TRANSACTION_ID: 'transaction_id', - TRANS_REFERENCE_NUMBER: 'auth_trans_ref_no', + DISPLAY_PAY_IN_ADVANCE_ALERT: 'displayPayInAdvanceAlert', + ERROR: 'error', LAST_FOUR: 'last_four', - DISPLAY_PAY_IN_ADVANCE_ALERT: 'displayPayInAdvanceAlert' + REFERENCE_NUMBER: 'req_reference_number', + REFERRAL_SEQ_NUM: 'referralseqnum', + SUBSCRIPTIONID: 'subscriptionid', + TRANS_REFERENCE_NUMBER: 'auth_trans_ref_no', + TRANSACTION_ID: 'transaction_id' + }); export default queryStrings; From ff5f8c5b29dcf2d3b84a38743bc199c70357ee6a Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Mon, 4 Mar 2024 16:06:54 -0500 Subject: [PATCH 607/674] Small tweaks --- src/helpers/order-helper.js | 37 ++++++++---- src/helpers/querystring-helper.js | 2 +- src/layouts/payment-return/payment-return.vue | 57 +++++++++++-------- src/router/index.js | 12 ++-- src/router/router-constants/routing-table.js | 4 +- src/store/index.js | 43 +++++++------- 6 files changed, 91 insertions(+), 64 deletions(-) diff --git a/src/helpers/order-helper.js b/src/helpers/order-helper.js index 85d0bec2..33e7d3c4 100644 --- a/src/helpers/order-helper.js +++ b/src/helpers/order-helper.js @@ -1,6 +1,17 @@ import { useMainStore } from '@/store'; import { updateOrCreateISSCookie } from '@/helpers/cookie-helper'; +/* + Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing +*/ +async function saveSessionHelper(store) { + const savedSessionInfo = await store.saveSession(); + if (savedSessionInfo) { + store.setSaveSessionInfo(savedSessionInfo.data); + } + updateOrCreateISSCookie(); +} + /* Will call API to save existing order, or create new one depending where it's called from. This will also set Referral information in the store after saving, and then @@ -8,8 +19,8 @@ import { updateOrCreateISSCookie } from '@/helpers/cookie-helper'; */ export async function saveSession({ shouldAwaitSaveSessionQueue = false }) { const store = useMainStore(); - var saveSessionPromise = store.applicationUser.saveSessionPromise - ? store.applicationUser.saveSessionPromise.then(() => { return saveSessionHelper(store); }) + const saveSessionPromise = store.applicationUser.saveSessionPromise + ? store.applicationUser.saveSessionPromise.then(() => saveSessionHelper(store)) : saveSessionHelper(store); store.setSaveSessionPromise(saveSessionPromise); @@ -20,12 +31,18 @@ export async function saveSession({ shouldAwaitSaveSessionQueue = false }) { } /* - Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing + Will determine if to submitWorkOrder. + TODO: Add more description to this */ -async function saveSessionHelper(store) { - const savedSessionInfo = await store.saveSession(); - if (savedSessionInfo) { - store.setSaveSessionInfo(savedSessionInfo.data); - } - updateOrCreateISSCookie(); -} \ No newline at end of file +export async function submitWorkOrder({ + pageNameToLog, + submitAfterSave = false, + createDeleteStatusWorkOrderForPia = false +}) { + await saveSession({ + pageNameToLog, + shouldAwaitSaveSessionQueue: true, + submitAfterSave, + createDeleteStatusWorkOrderForPia + }); +} diff --git a/src/helpers/querystring-helper.js b/src/helpers/querystring-helper.js index 32900e96..f4df1ed7 100644 --- a/src/helpers/querystring-helper.js +++ b/src/helpers/querystring-helper.js @@ -1,4 +1,4 @@ -export default function getQuerystringParameter(key) { +export default function getQueryStringParameter(key) { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const lowerCaseParams = new URLSearchParams(); diff --git a/src/layouts/payment-return/payment-return.vue b/src/layouts/payment-return/payment-return.vue index 1ef57a4b..329badf9 100644 --- a/src/layouts/payment-return/payment-return.vue +++ b/src/layouts/payment-return/payment-return.vue @@ -11,8 +11,10 @@ import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store/index.js'; import queryStrings from '@/constants/query-strings'; -import getQuerystringParameter from '@/helpers/querystring-helper.js'; +import getQueryStringParameter from '@/helpers/querystring-helper.js'; import { paymentMethods } from '@/constants/payment-method-constants.js'; +import { submitWorkOrder } from '@/helpers/order-helper.js'; +import showIssLoadingModal from '@/helpers/loading-modal-helper'; export default { name: 'payment-return', @@ -22,14 +24,14 @@ export default { }, mixins: [BaseFormMixin], async mounted() { - const payInAdvanceError = getQuerystringParameter(queryStrings.ERROR); + showIssLoadingModal(true); + const payInAdvanceError = getQueryStringParameter(queryStrings.ERROR); const { payInAdvanceType } = useMainStore().order.payment; if (payInAdvanceError) { console.error(`Error during payment: ${payInAdvanceError}`); const paymentPageNavScenario = - payInAdvanceType === paymentMethods.CREDIT_CARD - || payInAdvanceType === paymentMethods.AFTERPAY; + payInAdvanceType === paymentMethods.CREDIT_CARD || payInAdvanceType === paymentMethods.AFTERPAY; if (paymentPageNavScenario) { this.$router.navigate( this.navigationScenarios.PAY_IN_ADVANCE_CREDIT_CARD_ERROR, @@ -71,10 +73,16 @@ export default { arePagePrerequisitesValid() { return true; }, - async processCreditCardResponse() { - const subscriptionId = getQuerystringParameter(queryStrings.SUBSCRIPTIONID); + async processPaypalResponse() { + const token = getQueryStringParameter(queryStrings.TOKEN); + this.mainStore.updatePaypalToken(token); - const referralSeqNum = getQuerystringParameter(queryStrings.REFERRAL_SEQ_NUM); + await this.saveAndSubmitWorkOrder(); + }, + async processCreditCardResponse() { + const subscriptionId = getQueryStringParameter(queryStrings.SUBSCRIPTIONID); + + const referralSeqNum = getQueryStringParameter(queryStrings.REFERRAL_SEQ_NUM); if (referralSeqNum !== useMainStore().order.referralSequenceNumber) { console.error(`error: unknown ref:${referralSeqNum} ${useMainStore().order.referralSequenceNumber}`); this.$router.navigate( @@ -85,19 +93,19 @@ export default { } ); } else { - const expMonth = getQuerystringParameter(queryStrings.CARD_EXPIRATION_MONTH); - const expYear = getQuerystringParameter(queryStrings.CARD_EXPIRATION_YEAR); - const cardType = getQuerystringParameter(queryStrings.CARD_TYPE); - const billToPostalCode = getQuerystringParameter(queryStrings.BILL_TO_POSTAL_CODE); - const billToFirstName = getQuerystringParameter(queryStrings.BILL_TO_FIRST_NAME); - const billToLastName = getQuerystringParameter(queryStrings.BILL_TO_LAST_NAME); - const referenceNumber = getQuerystringParameter(queryStrings.REFERENCE_NUMBER); - const authCode = getQuerystringParameter(queryStrings.AUTH_CODE); - const transactionId = getQuerystringParameter(queryStrings.TRANSACTION_ID); - const transReferenceNumber = getQuerystringParameter(queryStrings.TRANS_REFERENCE_NUMBER); - const lastFour = getQuerystringParameter(queryStrings.LAST_FOUR); + const expMonth = getQueryStringParameter(queryStrings.CARD_EXPIRATION_MONTH); + const expYear = getQueryStringParameter(queryStrings.CARD_EXPIRATION_YEAR); + const cardType = getQueryStringParameter(queryStrings.CARD_TYPE); + const billToPostalCode = getQueryStringParameter(queryStrings.BILL_TO_POSTAL_CODE); + const billToFirstName = getQueryStringParameter(queryStrings.BILL_TO_FIRST_NAME); + const billToLastName = getQueryStringParameter(queryStrings.BILL_TO_LAST_NAME); + const referenceNumber = getQueryStringParameter(queryStrings.REFERENCE_NUMBER); + const authCode = getQueryStringParameter(queryStrings.AUTH_CODE); + const transactionId = getQueryStringParameter(queryStrings.TRANSACTION_ID); + const transReferenceNumber = getQueryStringParameter(queryStrings.TRANS_REFERENCE_NUMBER); + const lastFour = getQueryStringParameter(queryStrings.LAST_FOUR); - const ccToken = { + const creditCardToken = { subscriptionId, expMonth, expYear, @@ -111,7 +119,7 @@ export default { transReferenceNumber, lastFour }; - useMainStore().updateCCToken(ccToken); + useMainStore().updateCreditCardToken(creditCardToken); await this.saveAndSubmitWorkOrder(); } }, @@ -119,9 +127,10 @@ export default { // Final work order submit after returning from pay in advance. useMainStore().resetSubmittedOrder(); try { - // do we have a function to submit a work order, - // perhaps built into saveSession? - // we need to submit the work order here + await submitWorkOrder({ + pageNameToLog: 'payment-return', + submitAfterSave: true + }); } catch (error) { console.error(`error: response from submit work order:${error.message}`); this.$router.navigate( @@ -131,9 +140,11 @@ export default { [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true } ); + showIssLoadingModal(false); return; } + showIssLoadingModal(false); useMainStore().createSubmittedOrder(); this.$router.navigate( this.navigationScenarios.PAY_IN_ADVANCE_SUCCESS, diff --git a/src/router/index.js b/src/router/index.js index 4cd2dc45..fda08794 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -2,7 +2,7 @@ import { createWebHistory, createRouter } from 'vue-router'; import lazyLoadComponent from '@/router/dynamic-routing/component-loader'; import issPageValues from '@/router/router-constants/issPage-values'; -import { routingTable } from '@/router/router-constants/routing-table'; +import routingTable from '@/router/router-constants/routing-table'; import { useMainStore } from '@/store'; import eventBus from '@/helpers/event-bus/event-bus'; import { globalEvents, globalEventTypes } from '@/constants/events'; @@ -16,11 +16,9 @@ import showIssLoadingModal from '@/helpers/loading-modal-helper'; import analyticsMixin from '@/mixins/analytics-mixin'; import { saveSession } from '@/helpers/order-helper.js'; import routerParams from '@/router/router-constants/router-params'; -import bailoutCode from '@/constants/bailoutCode'; -import IssPageValues from '@/router/router-constants/issPage-values'; +import canBailoutNavigateBack from '@/helpers/bailout-helper'; +import bailoutMessage from '@/constants/bailoutMessage'; import navigationScenarios from './router-constants/navigation-scenarios'; -import canBailoutNavigateBack from "@/helpers/bailout-helper"; -import bailoutMessage from "@/constants/bailoutMessage"; const routes = [ { @@ -129,7 +127,7 @@ router.beforeEach(async (to, from) => { showIssLoadingModal(true); } - const isInIframe = fromQueryPage === IssPageValues.PAYMENT_PAGE; + const isInIframe = fromQueryPage === issPageValues.PAYMENT_PAGE; if (isInIframe) { // need to set window.top.location.href directly when navigating out of an iframe // especially when navigating with browser buttons @@ -139,7 +137,7 @@ router.beforeEach(async (to, from) => { const store = useMainStore(); // Prevent navigating backwards if we enter a bailout that we are not allowed to go back on - if (store.isBailout && from.name === IssPageValues.BAILOUT_PAGE && to.name !== 'root' && to.name !== IssPageValues.CONTACT_CONFIRMATION + if (store.isBailout && from.name === issPageValues.BAILOUT_PAGE && to.name !== 'root' && to.name !== issPageValues.CONTACT_CONFIRMATION && !canBailoutNavigateBack()) { return false; } diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index 60d76dcd..99582af8 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -655,7 +655,7 @@ const routingTable = () => [ { scenario: navigationScenarios.PAY_IN_ADVANCE_SUCCESS, destinationIssPageValue: issPageValues.CONFIRMATION - }, + } ] }, { @@ -763,4 +763,4 @@ const routingTable = () => [ ]; -export { routingTable }; +export default routingTable; diff --git a/src/store/index.js b/src/store/index.js index cc1b2986..6d8f8084 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -157,7 +157,8 @@ const getDefaultState = () => ({ parentAccountNumber: 0, isPayInAdvance: null, payInAdvanceType: null, - ccToken: { + paypalToken: null, + creditCardToken: { subscriptionId: null, expMonth: null, expYear: null, @@ -1202,7 +1203,7 @@ export const useMainStore = defineStore({ submitToMainframe: !!this.order.referralNumber, loadedFromDupeCheck }, - additionalSuccessEventDataHandler: (response) => + additionalSuccessEventDataHandler: () => `Email provided: ${customer.emailAddress ? 'true' : 'false'}` }).then((response) => { if (loadedFromDupeCheck) { @@ -1304,7 +1305,23 @@ export const useMainStore = defineStore({ throw ex; } }, - + 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; }, @@ -1399,7 +1416,7 @@ export const useMainStore = defineStore({ this.order.vehicle.registration.firstName = null; this.order.vehicle.registration.lastName = null; }, - resetServiceLocationAndDependencies(context) { + resetServiceLocationAndDependencies() { this.resetServiceLocationAppointmentType(); this.resetServiceLocationProvider(); this.resetSchedule(); @@ -2130,7 +2147,6 @@ export const useMainStore = defineStore({ this.resetInsurance(); this.resetBailout(); }, - savePaymentMethodChoice(paymentMethod) { const isPayInAdvance = paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE; this.order.payment.isPayInAdvance = isPayInAdvance; @@ -2144,21 +2160,6 @@ export const useMainStore = defineStore({ }); }, - updateCCToken(ccToken) { - this.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; - this.order.payment.ccToken.expMonth = ccToken.expMonth; - this.order.payment.ccToken.expYear = ccToken.expYear; - this.order.payment.ccToken.cardType = ccToken.cardType; - this.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; - this.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; - this.order.payment.ccToken.billToLastName = ccToken.billToLastName; - this.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; - this.order.payment.ccToken.authCode = ccToken.authCode; - this.order.payment.ccToken.transactionId = ccToken.transactionId; - this.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; - this.order.payment.ccToken.lastFour = ccToken.lastFour; - }, - hasSubmittedOrder() { return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; }, @@ -2183,7 +2184,7 @@ export const useMainStore = defineStore({ resetSubmittedOrder() { // clear from local storage window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); - }, + } }, persist: true From 76c35865e4fcf4141b78f6a050e1910983b44714 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Tue, 5 Mar 2024 10:41:47 -0500 Subject: [PATCH 608/674] Starting outline of tests --- .../coverage-statement.spec.js | 68 ++++--------------- 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index 79765a88..12f0b49a 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -118,59 +118,6 @@ describe.skip('coverageStatement.vue', () => { expect(arePagePrerequisitesValid).not.toBeTruthy(); }); }); - describe('Rendering', () => { - test('Should render site header', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const siteHeader = wrapper.findComponent({ ref: 'siteHeader' }); - - // Assert - expect(siteHeader.exists()).toBe(true); - }); - test('Should render site subheader', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const subheader = wrapper.find({ ref: 'siteSubHeader' }); - - // Assert - expect(subheader.exists()).toBe(true); - }); - - test('Should render explanatory text', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const explanatoryText = wrapper.find({ ref: 'explanatoryText' }); - - // Assert - expect(explanatoryText.exists()).toBe(true); - }); - test('Should render secondary text', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const secondaryText = wrapper.find({ ref: 'secondaryText' }); - - // Assert - expect(secondaryText.exists()).toBe(true); - }); - test('Should render site footer', () => { - // Arrange - const { wrapper } = getMountedComponent({}); - - // Act - const footer = wrapper.findComponent({ ref: 'siteFooter' }); - - // Assert - expect(footer.exists()).toBe(true); - }); - }); describe('Verified ITAC scenario', () => { test('If policy lookup successful, not No Comp, and deductible > service price, verifiedITAC returns true', () => { // Arrange @@ -881,6 +828,21 @@ describe('coverageStatement.vue-working', () => { // Assert expect(footer.exists()).toBe(true); }); + }); + describe('Computed', () => { + describe('formattedDeductible', () => {}); + describe('verifiedNoComp', () => {}); + describe('verifiedITAC', () => {}); + describe('verifiedDeductible', () => {}); + describe('unverified', () => {}); + describe('isADAS', () => {}); + describe('servicePriceForDisplay', () => {}); + describe('itacCostSavings', () => {}); + describe('itacCostSavingsForDisplay', () => {}); + describe('isQuoteDisplayed', () => {}); + }); + describe('watchers', () => { + }); describe('ITAC flag', () => { test('ITAC flag updated once component is initialized', async () => { From 9fd65de29ef1c5f3d421becc8d784127b91798fd Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 5 Mar 2024 10:43:50 -0500 Subject: [PATCH 609/674] but missing function back --- src/store/index.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/store/index.js b/src/store/index.js index 6d8f8084..2efd6470 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -949,7 +949,17 @@ export const useMainStore = defineStore({ }).then((response) => resolve(response), (error) => reject(error)); }); }, - + getCarrierAccountInfo() { + return new Promise((resolve, reject) => { + globalMethods.callHttpClient({ + method: endpoints.GetAccountInfo.method, + endpoint: endpoints.GetAccountInfo.url + this.issConfig.parentAccountNumber + }).then((response) => { + this.order.carrierPhoneNumber = response.data.phoneNumber; + return resolve(response.data); + }).catch((error) => reject(error)); + }); + }, async getSupportingItems() { const { glassParts } = this.lineItems; const { carId } = this.vehicle; From cf850358ae8b2591a37f5d4bb6bd053094482ff2 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Tue, 5 Mar 2024 10:44:35 -0500 Subject: [PATCH 610/674] Reverting problematic change --- src/store/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 3ba028ec..5017c884 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -950,7 +950,6 @@ export const useMainStore = defineStore({ const { glassParts } = this.lineItems; const { carId } = this.vehicle; const { isRepair, numberOfChips } = this.damage; - const { parentAccountNumber } = this.issConfig; return globalMethods .callHttpClient({ @@ -959,7 +958,7 @@ export const useMainStore = defineStore({ payload: { carId, damageType: isRepair ? 'Repair' : 'Replace', - parentAccountNumber, + parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER, parts: glassParts ?? [], numberOfRepairChips: isRepair ? numberOfChips : 0 } From d839c21244886ee96888f38ef2ecc354b07a4720 Mon Sep 17 00:00:00 2001 From: Josh Dassinger Date: Tue, 5 Mar 2024 09:46:36 -0600 Subject: [PATCH 611/674] SSR-600 Cannot continue existing claim --- .../duplicate-check/duplicate-check.vue | 14 +++-- src/store/index.js | 13 ++--- src/store/store.spec.js | 55 ++++++++++++++----- 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/layouts/duplicate-check/duplicate-check.vue b/src/layouts/duplicate-check/duplicate-check.vue index 7245adef..8f00a3ff 100644 --- a/src/layouts/duplicate-check/duplicate-check.vue +++ b/src/layouts/duplicate-check/duplicate-check.vue @@ -126,13 +126,17 @@ export default { * @summary Steps to perform when forward button clicked. */ async forwardButtonAction() { - if (this.selectedAnswer !== this.getNewOrderSelectionName) { - await useMainStore().loadSession() - .then(() => {}, () => {}) - .finally(() => { this.navigateForward(); }); - } else { + if (this.selectedAnswer === this.getNewOrderSelectionName) { this.navigateForward(); + return; } + + const duplicate = useMainStore().applicationUser.duplicateOrders.find((d) => d.referralNumber === this.selectedAnswer); + await useMainStore().loadSession(duplicate) + .catch(() => {}) + .finally(() => { + this.navigateForward(); + }); }, navigateForward() { if (!this.mainStore.order.policy.policyLookupSuccessful) { diff --git a/src/store/index.js b/src/store/index.js index 3ba028ec..befd4fd9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1210,20 +1210,17 @@ export const useMainStore = defineStore({ }); }, - async loadSession() { + async loadSession(duplicate) { 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(), + referralNumber: duplicate.referralNumber, + referralDate: duplicate.referralDate, parentAccountNumber: issConfig.parentAccountNumber, - referralCorrelationId: order.referralCorrelationId + referralCorrelationId: duplicate.referralCorrelationId } }); const { data } = response; @@ -1232,9 +1229,7 @@ export const useMainStore = defineStore({ return response; } - 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; diff --git a/src/store/store.spec.js b/src/store/store.spec.js index c15352b7..2c4525bf 100644 --- a/src/store/store.spec.js +++ b/src/store/store.spec.js @@ -961,10 +961,7 @@ describe('Store', () => { describe('loadSession method', () => { describe('successful method call', () => { const applicationUser = { - crmCustomerId: getRandomString(6, 6), - experiments: getRandomString(6, 6), - pageData: getRandomString(6, 6), - savedSessionId: getRandomString(6, 6) + experiments: getRandomString(6, 6) }; const vehicle = { year: getRandomString(6, 6), @@ -1006,9 +1003,13 @@ describe('Store', () => { it('calls load session api endpoint', async () => { // Arrange globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({ data: {} })); + const duplicate = { + referralNumber: getRandomString(6, 6), + referralCorrelationId: getRandomGuid() + }; // Act - store.loadSession(); + store.loadSession(duplicate); // Asserts expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining({ @@ -1020,9 +1021,13 @@ describe('Store', () => { // Arrange const response = { data: { ReferralNumber: getRandomString(6, 6) } }; globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response)); + const duplicate = { + referralNumber: getRandomString(6, 6), + referralCorrelationId: getRandomGuid() + }; // Act - const result = store.loadSession(); + const result = store.loadSession(duplicate); // Asserts await expect(result).resolves.toBe(response.data); @@ -1030,24 +1035,31 @@ describe('Store', () => { it('sets expected application user data', async () => { // Arrange globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse)); + const duplicate = { + referralNumber: getRandomString(6, 6), + referralCorrelationId: getRandomGuid() + }; // Act - await store.loadSession(); + await store.loadSession(duplicate); // Asserts expect(store.applicationUser.experiments).toEqual(applicationUser.experiments); - expect(store.applicationUser.savedSessionId).toBe(applicationUser.savedSessionId); - expect(store.applicationUser.crmCustomerId).toBe(applicationUser.crmCustomerId); }); it('sets expected vehicle data', async () => { // Arrange globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse)); + const duplicate = { + referralNumber: getRandomString(6, 6), + referralCorrelationId: getRandomGuid() + }; + store.order.policy.policyLookupSuccessful = true; store.policy.vehicles = [{ vin: vehicle.vin }]; // Act - await store.loadSession(); + await store.loadSession(duplicate); // Asserts expect(store.vehicle.year).toBe(vehicle.year); @@ -1061,11 +1073,16 @@ describe('Store', () => { // Arrange globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse)); + const duplicate = { + referralNumber: getRandomString(6, 6), + referralCorrelationId: getRandomGuid() + }; + store.order.policy.policyLookupSuccessful = true; store.policy.vehicles = [{ vin: vehicle.vin }]; // Act - await store.loadSession(); + await store.loadSession(duplicate); // Asserts expect(store.order.customer.address.streetAddress).toBe(customer.address.streetAddress); @@ -1081,10 +1098,14 @@ describe('Store', () => { it('sets expected remaining order data', async () => { // Arrange globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse)); - const originalWorkOrderNumber = store.order.workOrderNumber; + + const duplicate = { + referralNumber: getRandomString(6, 6), + referralCorrelationId: getRandomGuid() + }; // Act - await store.loadSession(); + await store.loadSession(duplicate); // Asserts expect(store.order.referralNumber).toBe(fullApiResponse.data.referralNumber); @@ -1092,7 +1113,6 @@ describe('Store', () => { expect(store.order.referralCorrelationId).toBe(fullApiResponse.data.referralCorrelationId); expect(store.order.referralSequenceNumber).toBe(fullApiResponse.data.referralSequenceNumber); expect(store.order.eon).toBe(fullApiResponse.data.eon); - expect(store.order.workOrderNumber).toBe(originalWorkOrderNumber); }); }); it('api call throws exception', async () => { @@ -1100,8 +1120,13 @@ describe('Store', () => { const error = 'load session error'; globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject(error)); + const duplicate = { + referralNumber: getRandomString(6, 6), + referralCorrelationId: getRandomGuid() + }; + // Act - await store.loadSession().catch((e) => { + await store.loadSession(duplicate).catch((e) => { expect(e).toEqual(error); }); From 844d1b0215ab3cc5a7f13f2e8cddde0f32d095e3 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 5 Mar 2024 11:22:00 -0500 Subject: [PATCH 612/674] unit tests --- .../order-confirmation.spec.js | 110 +++++++++++++++++- .../order-confirmation/order-confirmation.vue | 2 +- 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index 590b5c1b..1984ef04 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -12,10 +12,18 @@ import { createTestingPinia } from '@pinia/testing'; jest.mock('@/helpers/layout-helper.js', () => jest.fn()); jest.mock('@/helpers/cms-content-helper', () => ({ - fetchCmsContentForPage: jest.fn() + fetchCmsContentForPage: jest.fn(), + processIfStatements: jest.fn() })); const wordingText = 'wording Text {custom:address}'; +const inShopDuration = '60-90 minutes'; +jest.mock('@/helpers/date-helper', () => ({ + getDisplayTextForDurationLength: jest.fn().mockImplementation(() => inShopDuration), + convertDateStringToDate: jest.fn(), + get12HourTimeFormat: jest.fn() +})); + const mockMixin = { methods: { getCmsContent: jest.fn().mockImplementation(() => wordingText), @@ -34,12 +42,18 @@ const headerStub = { render: () => {} }; +const vehicleBannerStub = { + render: () => {} +}; + const initialStore = { order: { schedule: { date: '2024-03-01', startTime: '09:00', - endTime: '10:00' + endTime: '10:00', + jobMinMinutes: 60, + jobMaxMinutes: 90 }, serviceLocation: { address: '123 Test Way', @@ -70,7 +84,8 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu mountOptions.global.stubs = { siteFooter: footerStub, - siteHeader: headerStub + siteHeader: headerStub, + vehicleBanner: vehicleBannerStub }; const testingPinia = createTestingPinia({ @@ -110,6 +125,16 @@ describe('OrderConfirmation.vue', () => { // Assert expect(siteHeader.exists()).toBe(true); }); + test('Should render Vehicle Banner', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const vehicleBanner = wrapper.findComponent(vehicleBannerStub); + + // Assert + expect(vehicleBanner.exists()).toBe(true); + }); test('If Advanced flow, should display Site Footer', () => { // Arrange const testStore = { @@ -324,5 +349,84 @@ describe('OrderConfirmation.vue', () => { // Assert expect(testValue).toEqual('
    123 Safelite Street,
    Mesa, AZ 12345
    '); }); + test('appointmentWordingText2 should return Mobile text in expected format', () => { + // Arrange + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + address: '123 Test Way', + address2: '#1', + city: 'Mesa', + state: 'AZ', + zipCode: '12345', + appointmentType: 'Mobile' + } + } + }; + const { wrapper } = getMountedComponent(testStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText2; + + // Assert + expect(testValue).toEqual(wordingText); + }); + test('appointmentWordingText2 should return Drop Off and text in expected format', () => { + // Arrange + const testStore = { + order: { + schedule: { + date: '2019-01-01', + startTime: '09:00', + endTime: '10:00' + }, + serviceLocation: { + provider: { + address: { + streetAddress: '123 Safelite Street', + city: 'Mesa', + state: 'AZ', + zipCode: '12345' + } + }, + appointmentType: 'Drop Off' + } + } + }; + const { wrapper } = getMountedComponent(testStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText2; + const expected = wrapper.vm.getBodyText2FromCms('Test Widget'); + + // Assert + expect(testValue).toEqual(expected); + }); + test('appointmentWordingText2 should return In Shop text in expected format', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.appointmentWordingText2; + const expected = wrapper.vm.getBodyText2FromCms('Test Widget'); + + // Assert + expect(testValue).toEqual(expected); + }); + test('inShopAppointmentDuration should return appointment length', () => { + // Arrange + const { wrapper } = getMountedComponent(initialStore); + + // Act + const testValue = wrapper.vm.inShopAppointmentDuration; + + // Assert + expect(testValue).toEqual(inShopDuration); + }); }); }); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 4b299b07..25911e24 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -120,7 +120,7 @@ export default { // This conversion ensures we don't get get GMT induced date changes const dateObject = convertDateStringToDate(this.appointmentDate); // Ex: Tuesday, April 22 - return dateObject.toLocaleDateString('en-us', { + return dateObject?.toLocaleDateString('en-us', { weekday: 'long', month: 'long', day: 'numeric' From b8712cbf5ef15051c9ffbf48baefef5b996a87ca Mon Sep 17 00:00:00 2001 From: Matt Caimi Date: Tue, 5 Mar 2024 11:24:47 -0500 Subject: [PATCH 613/674] SSR-1081 break up processCreditCardResponse --- src/layouts/payment-return/payment-return.vue | 73 ++++++++----------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/src/layouts/payment-return/payment-return.vue b/src/layouts/payment-return/payment-return.vue index 329badf9..8e5d3de6 100644 --- a/src/layouts/payment-return/payment-return.vue +++ b/src/layouts/payment-return/payment-return.vue @@ -23,6 +23,24 @@ export default { Form }, mixins: [BaseFormMixin], + computed: { + creditCardToken() { + return { + subscriptionId: getQueryStringParameter(queryStrings.SUBSCRIPTIONID), + expMonth: getQueryStringParameter(queryStrings.CARD_EXPIRATION_MONTH), + expYear: getQueryStringParameter(queryStrings.CARD_EXPIRATION_YEAR), + cardType: getQueryStringParameter(queryStrings.CARD_TYPE), + billToPostalCode: getQueryStringParameter(queryStrings.BILL_TO_POSTAL_CODE), + billToFirstName: getQueryStringParameter(queryStrings.BILL_TO_FIRST_NAME), + billToLastName: getQueryStringParameter(queryStrings.BILL_TO_LAST_NAME), + referenceNumber: getQueryStringParameter(queryStrings.REFERENCE_NUMBER), + authCode: getQueryStringParameter(queryStrings.AUTH_CODE), + transactionId: getQueryStringParameter(queryStrings.TRANSACTION_ID), + transReferenceNumber: getQueryStringParameter(queryStrings.TRANS_REFERENCE_NUMBER), + lastFour: getQueryStringParameter(queryStrings.LAST_FOUR) + }; + } + }, async mounted() { showIssLoadingModal(true); const payInAdvanceError = getQueryStringParameter(queryStrings.ERROR); @@ -73,6 +91,15 @@ export default { arePagePrerequisitesValid() { return true; }, + navigateOnPayInAdvanceError() { + this.$router.navigate( + this.navigationScenarios.PAY_IN_ADVANCE_ERROR, + this.$route, + { + [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true + } + ); + }, async processPaypalResponse() { const token = getQueryStringParameter(queryStrings.TOKEN); this.mainStore.updatePaypalToken(token); @@ -80,46 +107,12 @@ export default { await this.saveAndSubmitWorkOrder(); }, async processCreditCardResponse() { - const subscriptionId = getQueryStringParameter(queryStrings.SUBSCRIPTIONID); - const referralSeqNum = getQueryStringParameter(queryStrings.REFERRAL_SEQ_NUM); if (referralSeqNum !== useMainStore().order.referralSequenceNumber) { console.error(`error: unknown ref:${referralSeqNum} ${useMainStore().order.referralSequenceNumber}`); - this.$router.navigate( - this.navigationScenarios.PAY_IN_ADVANCE_ERROR, - this.$route, - { - [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true - } - ); + this.navigateOnPayInAdvanceError(); } else { - const expMonth = getQueryStringParameter(queryStrings.CARD_EXPIRATION_MONTH); - const expYear = getQueryStringParameter(queryStrings.CARD_EXPIRATION_YEAR); - const cardType = getQueryStringParameter(queryStrings.CARD_TYPE); - const billToPostalCode = getQueryStringParameter(queryStrings.BILL_TO_POSTAL_CODE); - const billToFirstName = getQueryStringParameter(queryStrings.BILL_TO_FIRST_NAME); - const billToLastName = getQueryStringParameter(queryStrings.BILL_TO_LAST_NAME); - const referenceNumber = getQueryStringParameter(queryStrings.REFERENCE_NUMBER); - const authCode = getQueryStringParameter(queryStrings.AUTH_CODE); - const transactionId = getQueryStringParameter(queryStrings.TRANSACTION_ID); - const transReferenceNumber = getQueryStringParameter(queryStrings.TRANS_REFERENCE_NUMBER); - const lastFour = getQueryStringParameter(queryStrings.LAST_FOUR); - - const creditCardToken = { - subscriptionId, - expMonth, - expYear, - cardType, - billToPostalCode, - billToFirstName, - billToLastName, - referenceNumber, - authCode, - transactionId, - transReferenceNumber, - lastFour - }; - useMainStore().updateCreditCardToken(creditCardToken); + useMainStore().updateCreditCardToken(this.creditCardToken); await this.saveAndSubmitWorkOrder(); } }, @@ -133,13 +126,7 @@ export default { }); } catch (error) { console.error(`error: response from submit work order:${error.message}`); - this.$router.navigate( - this.navigationScenarios.PAY_IN_ADVANCE_ERROR, - this.$route, - { - [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: true - } - ); + this.navigateOnPayInAdvanceError(); showIssLoadingModal(false); return; } From 2f5883be5a5f6c291834f8ac99b3049025a7b8b7 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Tue, 5 Mar 2024 11:34:08 -0500 Subject: [PATCH 614/674] fix a merge issue --- src/store/index.js | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 0bbf894c..b0d7fb10 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -20,7 +20,6 @@ import { noCoverageForSelectedVehicle, repairWaivedForSelectedVehicle } from '@/helpers/policy-vehicle-helper'; -import webStorageConstants from '@/constants/web-storage-constants'; const storeId = 'main'; @@ -2196,48 +2195,6 @@ export const useMainStore = defineStore({ // clear from local storage window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); } - - updateCCToken(ccToken) { - this.order.payment.ccToken.subscriptionId = ccToken.subscriptionId; - this.order.payment.ccToken.expMonth = ccToken.expMonth; - this.order.payment.ccToken.expYear = ccToken.expYear; - this.order.payment.ccToken.cardType = ccToken.cardType; - this.order.payment.ccToken.billToPostalCode = ccToken.billToPostalCode; - this.order.payment.ccToken.billToFirstName = ccToken.billToFirstName; - this.order.payment.ccToken.billToLastName = ccToken.billToLastName; - this.order.payment.ccToken.referenceNumber = ccToken.referenceNumber; - this.order.payment.ccToken.authCode = ccToken.authCode; - this.order.payment.ccToken.transactionId = ccToken.transactionId; - this.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber; - this.order.payment.ccToken.lastFour = ccToken.lastFour; - }, - - hasSubmittedOrder() { - return window.sessionStorage.getItem(webStorageConstants.SUBMITTED_ORDER) !== null; - }, - - createSubmittedOrder() { - if (this.hasSubmittedOrder()) { - return; - } - const submittedOrder = this.order; - const { experiments } = this.applicationUser; - - // set to local storage - window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); - - // clear vuex - this.resetState(); - - // restore user's experiments - this.applicationUser.experiments = experiments; - }, - - resetSubmittedOrder() { - // clear from local storage - window.sessionStorage.removeItem(webStorageConstants.SUBMITTED_ORDER); - }, - }, persist: true }); From ddb49a8e7ce2fb85d06ed74dd7669b9119d68b91 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 5 Mar 2024 13:26:12 -0500 Subject: [PATCH 615/674] final fixes --- .../order-confirmation.spec.js | 17 ----------------- .../order-confirmation/order-confirmation.vue | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index 1984ef04..d53eacbd 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -17,13 +17,6 @@ jest.mock('@/helpers/cms-content-helper', () => ({ })); const wordingText = 'wording Text {custom:address}'; -const inShopDuration = '60-90 minutes'; -jest.mock('@/helpers/date-helper', () => ({ - getDisplayTextForDurationLength: jest.fn().mockImplementation(() => inShopDuration), - convertDateStringToDate: jest.fn(), - get12HourTimeFormat: jest.fn() -})); - const mockMixin = { methods: { getCmsContent: jest.fn().mockImplementation(() => wordingText), @@ -418,15 +411,5 @@ describe('OrderConfirmation.vue', () => { // Assert expect(testValue).toEqual(expected); }); - test('inShopAppointmentDuration should return appointment length', () => { - // Arrange - const { wrapper } = getMountedComponent(initialStore); - - // Act - const testValue = wrapper.vm.inShopAppointmentDuration; - - // Assert - expect(testValue).toEqual(inShopDuration); - }); }); }); diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 25911e24..4b299b07 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -120,7 +120,7 @@ export default { // This conversion ensures we don't get get GMT induced date changes const dateObject = convertDateStringToDate(this.appointmentDate); // Ex: Tuesday, April 22 - return dateObject?.toLocaleDateString('en-us', { + return dateObject.toLocaleDateString('en-us', { weekday: 'long', month: 'long', day: 'numeric' From a1b66955220c44c7bc272d858cc644d8db4ab272 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 5 Mar 2024 14:05:00 -0500 Subject: [PATCH 616/674] PR feedback refactoring, unit test fixes --- .../order-confirmation.spec.js | 6 ++--- .../order-confirmation/order-confirmation.vue | 27 ++++++++++--------- src/store/index.js | 1 + 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.spec.js b/src/layouts/order-confirmation/order-confirmation.spec.js index d53eacbd..5883b9d1 100644 --- a/src/layouts/order-confirmation/order-confirmation.spec.js +++ b/src/layouts/order-confirmation/order-confirmation.spec.js @@ -233,7 +233,7 @@ describe('OrderConfirmation.vue', () => { endTime: '10:00' }, serviceLocation: { - appointmentType: 'Drop Off' + appointmentType: 'Dropoff' } } }; @@ -300,7 +300,7 @@ describe('OrderConfirmation.vue', () => { zipCode: '12345' } }, - appointmentType: 'Drop Off' + appointmentType: 'Dropoff' } } }; @@ -387,7 +387,7 @@ describe('OrderConfirmation.vue', () => { zipCode: '12345' } }, - appointmentType: 'Drop Off' + appointmentType: 'Dropoff' } } }; diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index 4b299b07..d6c7b2d2 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -61,6 +61,7 @@ import { useMainStore } from '@/store'; import { get12HourTimeFormat, get12HourTimeMobileFormat, convertDateStringToDate, getDisplayTextForDurationLength } from '@/helpers/date-helper.js'; import { toTitleCase } from '@/helpers/text-helper.js'; +import { AppointmentTypeStrings } from '@/constants/schedule-constants'; export default { name: 'order-confirmation', @@ -105,7 +106,7 @@ export default { return this.getCmsContent('OrderConfirmationContent', 'Image'); }, appointmentType() { - return this.mainStore.order.serviceLocation.appointmentType.toUpperCase(); + return this.mainStore.order.serviceLocation.appointmentType; }, appointmentDate() { return this.mainStore.order.schedule.date; @@ -179,17 +180,17 @@ export default { }, appointmentWordingText() { switch (this.appointmentType) { - case 'MOBILE': + case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: return this.mobileWordingText?.replaceAll( '{custom:address}', this.serviceLocationFullAddress ); - case 'DROP OFF': + case AppointmentTypeStrings.DROP_OFF: return this.dropOffAndInShopWordingText?.replaceAll( '{custom:address}', this.providerFullAddress ); - case 'INSHOP': + case AppointmentTypeStrings.IN_SHOP: return this.dropOffAndInShopWordingText?.replaceAll( '{custom:address}', this.providerFullAddress @@ -200,11 +201,11 @@ export default { }, appointmentWordingText2() { switch (this.appointmentType) { - case 'MOBILE': + case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: return this.mobileWordingText2; - case 'DROP OFF': + case AppointmentTypeStrings.DROP_OFF: return this.dropOffAndInShopWordingText2; - case 'INSHOP': + case AppointmentTypeStrings.IN_SHOP: return this.dropOffAndInShopWordingText2?.replaceAll( '{custom:inShopDuration}', this.inShopAppointmentDuration @@ -214,13 +215,13 @@ export default { } }, mobileAppointment() { - return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'MOBILE'; + return useMainStore().getters.isMobileAppointment; }, inShopAppointment() { - return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'INSHOP'; + return useMainStore().getters.isInShopAppointment; }, dropOffAppointment() { - return this.mainStore.order.serviceLocation.appointmentType.toUpperCase() === 'DROP OFF'; + return useMainStore().getters.isDropOffAppointment; }, inShopAppointmentDuration() { const inshopDurationTime = getDisplayTextForDurationLength( @@ -241,12 +242,12 @@ export default { }, formatAppointmentTime(appointmentType) { switch (appointmentType) { - case 'MOBILE': + case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: // eslint-disable-next-line max-len return `Between ${get12HourTimeMobileFormat(this.appointmentStartTime)} - ${get12HourTimeMobileFormat(this.appointmentEndTime)}`; - case 'DROP OFF': + case AppointmentTypeStrings.DROP_OFF: return 'Drop off before 9:30 AM'; - case 'INSHOP': + case AppointmentTypeStrings.IN_SHOP: return `at ${get12HourTimeFormat(this.appointmentStartTime)}`; default: return null; diff --git a/src/store/index.js b/src/store/index.js index 5017c884..e34a7fcd 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -237,6 +237,7 @@ export const useMainStore = defineStore({ 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.payment.insuranceCoverage.claimNumber !== null, isBailout: (state) => state.applicationUser.pageData[issPageValues.BAILOUT_PAGE] != null, From 018e27679afb67706f3cf004621667b526b1a1a6 Mon Sep 17 00:00:00 2001 From: Katie Kroell Date: Tue, 5 Mar 2024 14:22:12 -0500 Subject: [PATCH 617/674] logic/prereq updates --- .../order-confirmation/order-confirmation.vue | 15 +++++++++------ src/layouts/payment-method/payment-method.vue | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index d6c7b2d2..f1bddf9e 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -180,7 +180,8 @@ export default { }, appointmentWordingText() { switch (this.appointmentType) { - case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: + case AppointmentTypeStrings.MOBILE: + case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: return this.mobileWordingText?.replaceAll( '{custom:address}', this.serviceLocationFullAddress @@ -201,7 +202,8 @@ export default { }, appointmentWordingText2() { switch (this.appointmentType) { - case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: + case AppointmentTypeStrings.MOBILE: + case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: return this.mobileWordingText2; case AppointmentTypeStrings.DROP_OFF: return this.dropOffAndInShopWordingText2; @@ -215,13 +217,13 @@ export default { } }, mobileAppointment() { - return useMainStore().getters.isMobileAppointment; + return this.mainStore.isMobileAppointment; }, inShopAppointment() { - return useMainStore().getters.isInShopAppointment; + return this.mainStore.isInShopAppointment; }, dropOffAppointment() { - return useMainStore().getters.isDropOffAppointment; + return this.mainStore.isDropOffAppointment; }, inShopAppointmentDuration() { const inshopDurationTime = getDisplayTextForDurationLength( @@ -242,7 +244,8 @@ export default { }, formatAppointmentTime(appointmentType) { switch (appointmentType) { - case AppointmentTypeStrings.MOBILE || AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: + case AppointmentTypeStrings.MOBILE: + case AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP: // eslint-disable-next-line max-len return `Between ${get12HourTimeMobileFormat(this.appointmentStartTime)} - ${get12HourTimeMobileFormat(this.appointmentEndTime)}`; case AppointmentTypeStrings.DROP_OFF: diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 8b03a875..ab362f4c 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -178,7 +178,8 @@ export default { && providerLocation.zipCode ); - const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE; + const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE + || serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; const serviceLocationReqs = (isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs); From 7757bc6cfd78f02a0aee58623c4726de50f72f17 Mon Sep 17 00:00:00 2001 From: Michaela Brydon Date: Wed, 6 Mar 2024 10:15:08 -0500 Subject: [PATCH 618/674] Adding test cases --- .../coverage-statement.spec.js | 57 +++++++++++++-- .../coverage-statement/coverage-statement.vue | 70 ++++++++----------- 2 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/layouts/coverage-statement/coverage-statement.spec.js b/src/layouts/coverage-statement/coverage-statement.spec.js index 12f0b49a..186c1799 100644 --- a/src/layouts/coverage-statement/coverage-statement.spec.js +++ b/src/layouts/coverage-statement/coverage-statement.spec.js @@ -830,19 +830,62 @@ describe('coverageStatement.vue-working', () => { }); }); describe('Computed', () => { - describe('formattedDeductible', () => {}); - describe('verifiedNoComp', () => {}); - describe('verifiedITAC', () => {}); - describe('verifiedDeductible', () => {}); + describe.only('verifiedNoComp', () => { + test.each([true, false])('returns false when policyLookupSuccessful false', (isNoComp) => { + + }); + test.each([true, false])('returns false when isNoComp false', (policyLookupSuccessful) => {}); + test('returns true when policyLookupSuccessful true and policyLookupSuccessful true', () => { + + }); + }); + describe('verifiedITAC', () => { + test('returns false when policyLookupSuccessful false', () => {}); + test('returns false when isNoComp true', () => {}); + test('returns false when deductibleValue equals totalServicePrice', () => {}); + test('returns false when deductibleValue less than totalServicePrice', () => {}); + }); + describe('verifiedDeductible', () => { + test('', () => { }); + test('', () => { }); + test('', () => { }); + test('', () => { }); + test('', () => { }); + test('', () => { }); + test('', () => { }); + }); describe('unverified', () => {}); describe('isADAS', () => {}); - describe('servicePriceForDisplay', () => {}); describe('itacCostSavings', () => {}); - describe('itacCostSavingsForDisplay', () => {}); describe('isQuoteDisplayed', () => {}); + describe('shouldRegisterClaim', () => {}); }); - describe('watchers', () => { + describe('methods', () => { + describe('arePagePrerequisitesValid', () => { + }); + test.each([ + [0, '$0.00'], + [1, '$1.00'], + [12, '$12.00'], + [1.2, '$1.20'], + [1.25, '$1.25'], + [1.254, '$1.25'], + [1.255, '$1.26'], + [-1, '-$1.00'] + ])('getFormattedAmount', (value, expected) => { + // Arrange + const { wrapper } = getMountedComponent(); + + // Act + const result = wrapper.vm.getFormattedAmount(value); + + // Assert + expect(result).toBe(expected); + }); + describe('navigateForward', () => { + + }); }); describe('ITAC flag', () => { test('ITAC flag updated once component is initialized', async () => { diff --git a/src/layouts/coverage-statement/coverage-statement.vue b/src/layouts/coverage-statement/coverage-statement.vue index 8776ebe1..ad578df1 100644 --- a/src/layouts/coverage-statement/coverage-statement.vue +++ b/src/layouts/coverage-statement/coverage-statement.vue @@ -35,7 +35,7 @@
    - {{ formattedDeductible }} + {{ deductibleForDisplay }}
    {{ deductibleText }}  - {{ formattedDeductible }} + {{ deductibleForDisplay }}
    { - useMainStore() - .setBailout( - to, - bailoutMessage.pricingResponseError( - availableLineItems.map((li) => li.partNumber), - { code: err.code, message: err.message, data: err.data } - ) - ); + setBailout(to, bailoutMessage.pricingResponseError( + availableLineItems.map((li) => li.partNumber), + { code: err.code, message: err.message, data: err.data } + )); hasBailedOut = true; next(`/?issPage=${issPageValues.BAILOUT_PAGE}`); }); @@ -292,7 +292,7 @@ export default { deductibleValue() { return useMainStore().order.currentDeductible; }, - formattedDeductible() { + deductibleForDisplay() { return this.getFormattedAmount(this.deductibleValue); }, registerClaimSuccessful() { @@ -347,6 +347,13 @@ export default { }, isQuoteDisplayed() { return this.verifiedITAC || this.verifiedNoComp; + }, + shouldRegisterClaim() { + return this.policyLookupSuccessful + && useMainStore().vehicle.policyVehicleId >= 0 + && useMainStore().isClaimRegistrationRequired + && !useMainStore().isClaimAlreadyRegistered + && (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC); } }, watch: { @@ -373,11 +380,7 @@ export default { }, async initializeComponent() { useMainStore().updatePolicyITACFlag(this.verifiedITAC); - if (this.policyLookupSuccessful - && useMainStore().vehicle.policyVehicleId >= 0 - && useMainStore().isClaimRegistrationRequired - && !useMainStore().isClaimAlreadyRegistered - && (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC)) { + if (this.shouldRegisterClaim) { await useMainStore().registerClaim()?.catch(() => {}); } this.$refs.loadingModal.hideModal(); @@ -385,38 +388,27 @@ export default { async navigateForward() { if (this.unverified || this.verifiedDeductible) { useMainStore().updateSupportingItems(this.supportingItems); - this.$router.navigate( - navigationScenarios.CLICKED_FORWARD, - this.$route, - {}, - { [routerParams.SAVE_SESSION_SYNCHRONOUS]: true } - ); + this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD); } else if (this.verifiedITAC || this.verifiedNoComp) { useMainStore().updateIsSafeliteProvider(this.selectedProvider === SAFELITE_PROVIDER); if (this.selectedProvider === SAFELITE_PROVIDER) { useMainStore().updateSupportingItems(this.supportingItems); - this.$router.navigate( - navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, - this.$route - ); + this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE); } else { - useMainStore().setBailout(this.$router.currentRoute, bailoutMessage.RequestCallback()); - this.$router.navigate( - navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, - this.$route - ); + this.setBailoutWithMessage(bailoutMessage.RequestCallback()); + this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP); } } else { - useMainStore().setBailout( - this.$router.currentRoute, - bailoutMessage.coverageStatementInvalidState() - ); - this.$router.navigate( - navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE, - this.$route - ); + this.setBailoutWithMessage(bailoutMessage.coverageStatementInvalidState()); + this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE); } }, + setBailoutWithMessage(message) { + setBailout(this.$router.currentRoute, message); + }, + navigateWithScenario(scenario) { + this.$router.navigate(scenario, this.$route); + }, getTextFromCmsWithCustomIfStatements(widgetName, widgetField) { const rawText = this.getCmsContent(widgetName, widgetField); return processIfStatements(rawText, 'custom', this.getCustomValueFromString); From 6c013bc0adeac055a88519190762599a992c8caa Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 6 Mar 2024 15:58:33 -0500 Subject: [PATCH 619/674] AfterPay Updates --- src/constants/endpoints.js | 4 + .../vehicle-banner/vehicle-banner.vue | 8 +- .../order-confirmation/order-confirmation.vue | 56 ++++--- src/layouts/payment-method/payment-method.vue | 1 - src/layouts/payment-page/payment-page.vue | 97 ++++++++++-- src/mixins/base-mixin.js | 52 ++++++ src/router/index.js | 31 +++- src/router/router-constants/routing-table.js | 2 +- src/store/index.js | 148 +++++++++++++++++- 9 files changed, 352 insertions(+), 47 deletions(-) diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 8bd893e9..3e6a617e 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -116,6 +116,10 @@ const endpoints = Object.freeze({ url: `${ACCOUNT_BASE_URL}/`, method: 'GET' }, + TaxOrderItems: { + url: '/price/api/v1/price/taxed-order-items', + method: 'GET' + }, LogExperimentExposureIfAssigned: { url: `${EXPERIMENTS_BASE_URL}/log-exposure`, method: 'POST' diff --git a/src/iss-components/vehicle-banner/vehicle-banner.vue b/src/iss-components/vehicle-banner/vehicle-banner.vue index d86e7bfc..387118c1 100644 --- a/src/iss-components/vehicle-banner/vehicle-banner.vue +++ b/src/iss-components/vehicle-banner/vehicle-banner.vue @@ -23,7 +23,13 @@ export default { return this.genericVehicleImage; } - const { imageUrl } = this.mainStore.order.vehicle; + let imageUrl = ''; + if (this.mainStore.hasSubmittedOrder()) { + imageUrl = this.mainStore.submittedOrder.vehicle.imageUrl; + } else { + imageUrl = this.mainStore.order.vehicle.imageUrl; + } + if (!imageUrl || imageUrl === 'NULL') { return this.getUnmatchedVehicleIcon(); } diff --git a/src/layouts/order-confirmation/order-confirmation.vue b/src/layouts/order-confirmation/order-confirmation.vue index f1bddf9e..6d94001d 100644 --- a/src/layouts/order-confirmation/order-confirmation.vue +++ b/src/layouts/order-confirmation/order-confirmation.vue @@ -58,7 +58,9 @@ import settleAllPromises from '@/helpers/layout-helper'; import { Form } from 'vee-validate'; import BaseFormMixin from '@/mixins/base-form-mixin.js'; import { useMainStore } from '@/store'; -import { get12HourTimeFormat, get12HourTimeMobileFormat, convertDateStringToDate, +import { get12HourTimeFormat, + get12HourTimeMobileFormat, + convertDateStringToDate, getDisplayTextForDurationLength } from '@/helpers/date-helper.js'; import { toTitleCase } from '@/helpers/text-helper.js'; import { AppointmentTypeStrings } from '@/constants/schedule-constants'; @@ -66,14 +68,15 @@ import { AppointmentTypeStrings } from '@/constants/schedule-constants'; export default { name: 'order-confirmation', components: { + // eslint-disable-next-line vue/no-reserved-component-names + Form, siteHeader, vehicleBanner, - siteFooter, - // eslint-disable-next-line vue/no-reserved-component-names - Form + siteFooter }, mixins: [BaseFormMixin], async beforeRouteEnter(to, from, next) { + useMainStore().createSubmittedOrder(); // Call APIs const cmsContentPromise = fetchCmsContentForPage(to.query.issPage); // Settle promises and get results @@ -90,7 +93,8 @@ export default { }, setup() { const mainStore = useMainStore(); - return { mainStore }; + const { submittedOrder } = mainStore; + return { mainStore, submittedOrder }; }, computed: { carrierName() { @@ -106,16 +110,16 @@ export default { return this.getCmsContent('OrderConfirmationContent', 'Image'); }, appointmentType() { - return this.mainStore.order.serviceLocation.appointmentType; + return this.submittedOrder.serviceLocation.appointmentType; }, appointmentDate() { - return this.mainStore.order.schedule.date; + return this.submittedOrder.schedule.date; }, appointmentStartTime() { - return this.mainStore.order.schedule.startTime; + return this.submittedOrder.schedule.startTime; }, appointmentEndTime() { - return this.mainStore.order.schedule.endTime; + return this.submittedOrder.schedule.endTime; }, appointmentDateFormatted() { // This conversion ensures we don't get get GMT induced date changes @@ -144,35 +148,35 @@ export default { return this.getBodyText2FromCms('DropOffAndInShopWordingWidget'); }, serviceLocationAddress() { - return this.mainStore.order.serviceLocation.address; + return this.submittedOrder.serviceLocation.address; }, serviceLocationAddress2() { - return this.mainStore.order.serviceLocation.address2; + return this.submittedOrder.serviceLocation.address2; }, serviceLocationCity() { - return this.mainStore.order.serviceLocation.city; + return this.submittedOrder.serviceLocation.city; }, serviceLocationState() { - return this.mainStore.order.serviceLocation.state; + return this.submittedOrder.serviceLocation.state; }, serviceLocationZipCode() { - return this.mainStore.order.serviceLocation.zipCode; + return this.submittedOrder.serviceLocation.zipCode; }, serviceLocationFullAddress() { // eslint-disable-next-line max-len - return `
    ${this.serviceLocationAddress}, ${this.serviceLocationAddress2 ? `${this.serviceLocationAddress2},` : ''}
    ${this.serviceLocationCity}, ${this.serviceLocationState} ${this.serviceLocationZipCode}
    `; + return `${this.serviceLocationAddress}, ${this.serviceLocationAddress2 ? `${this.serviceLocationAddress2},` : ''}
    ${this.serviceLocationCity}, ${this.serviceLocationState} ${this.serviceLocationZipCode}`; }, providerAddress() { - return toTitleCase(this.mainStore.order.serviceLocation.provider.address.streetAddress); + return toTitleCase(this.submittedOrder.serviceLocation.provider.address.streetAddress); }, providerCity() { - return toTitleCase(this.mainStore.order.serviceLocation.provider.address.city); + return toTitleCase(this.submittedOrder.serviceLocation.provider.address.city); }, providerState() { - return this.mainStore.order.serviceLocation.provider.address.state; + return this.submittedOrder.serviceLocation.provider.address.state; }, providerZipCode() { - return this.mainStore.order.serviceLocation.provider.address.zipCode; + return this.submittedOrder.serviceLocation.provider.address.zipCode; }, providerFullAddress() { // eslint-disable-next-line max-len @@ -217,18 +221,19 @@ export default { } }, mobileAppointment() { - return this.mainStore.isMobileAppointment; + return this.submittedOrder.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE + || this.submittedOrder.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; }, inShopAppointment() { - return this.mainStore.isInShopAppointment; + return this.submittedOrder.serviceLocation.appointmentType === AppointmentTypeStrings.IN_SHOP; }, dropOffAppointment() { - return this.mainStore.isDropOffAppointment; + return this.submittedOrder.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF; }, inShopAppointmentDuration() { const inshopDurationTime = getDisplayTextForDurationLength( - this.mainStore.order.schedule.jobMinMinutes, - this.mainStore.order.schedule.jobMaxMinutes + this.submittedOrder.schedule.jobMinMinutes, + this.submittedOrder.schedule.jobMaxMinutes ); return inshopDurationTime; } @@ -310,6 +315,9 @@ $page-side-padding: 1.5rem; } .appointment-text { + :deep(p) { + margin: 0; + } :deep(strong) { font-weight: $font-weight-bold; color: $black; diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index ab362f4c..c7440bf6 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -33,7 +33,6 @@ ref="siteFooter" cmsWidgetName="SiteFooterWidget" :isForwardActionDisabled="!meta.valid" - :isBackButtonHidden="shouldHideBackButton" :isStackedVertically="true" @backClicked="navigateBack" @ForwardClicked="forwardButtonAction" /> diff --git a/src/layouts/payment-page/payment-page.vue b/src/layouts/payment-page/payment-page.vue index 1f77de74..85c7f707 100644 --- a/src/layouts/payment-page/payment-page.vue +++ b/src/layouts/payment-page/payment-page.vue @@ -1,9 +1,5 @@