From 34c6a1651e69a824971c2c8a88c4df5eb189e6e9 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Mon, 5 Jan 2026 10:52:25 -0500 Subject: [PATCH 01/49] Update styles/layout for service-location parity - Updated subheader on service-location - Update list-button styles so that inshop/mobile buttons match heritage --- .../button-question/button-question.vue | 2 +- .../appointment-type-question.vue | 46 +++++++++---------- .../service-location/service-location.vue | 32 ++++--------- src/styles/shared-input-button-styles.scss | 12 +---- src/styles/ux-variables.scss | 1 + src/ux-components/list-button/list-button.vue | 25 +++++----- 6 files changed, 46 insertions(+), 72 deletions(-) diff --git a/src/digital-components/button-question/button-question.vue b/src/digital-components/button-question/button-question.vue index 5c380612..2df23f7b 100644 --- a/src/digital-components/button-question/button-question.vue +++ b/src/digital-components/button-question/button-question.vue @@ -329,7 +329,7 @@ export default { } .question-text { - margin-bottom: 1rem; + margin-bottom: .625rem; font-size: 1rem; line-height: 1.625rem; 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 index ad3bf61d..41c0353d 100644 --- a/src/layouts/service-location/appointment-type-question/appointment-type-question.vue +++ b/src/layouts/service-location/appointment-type-question/appointment-type-question.vue @@ -1,24 +1,23 @@ diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index e4843e92..bed11abc 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -12,8 +12,8 @@
- + - diff --git a/src/store/index.js b/src/store/index.js index 14106bf2..ef1b7f52 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1011,14 +1011,13 @@ export const useMainStore = defineStore({ }); }, - getProviders(serviceZipCode) { + getProviders(serviceZipCode, shopRadiusInMiles = 100) { const { carId, isBigTruck } = this.order.vehicle; const damageType = this.damage.isRepair ? 'Repair' : 'Replace'; const { parentAccountNumber } = this.order; const partsWithRecal = getTopLevelGlassPartsWithRecal(this.order.lineItems.glassParts); const windshieldPartWithRecal = partsWithRecal?.length > 0 ? partsWithRecal[0] : null; const safeliteOnly = true; - const shopRadiusInMiles = 100; let url = `${endpoints.GetProviders.url}/${serviceZipCode}/${damageType}/${shopRadiusInMiles}/${parentAccountNumber}/${safeliteOnly}/${carId}`; if (windshieldPartWithRecal) { diff --git a/src/styles/ux-variables.scss b/src/styles/ux-variables.scss index 47914dbd..56bd5bad 100644 --- a/src/styles/ux-variables.scss +++ b/src/styles/ux-variables.scss @@ -145,7 +145,7 @@ $font-weight-lighter: lighter; $font-weight-light: 300; $font-weight-normal: 400; $font-weight-bold: 500; -$font-weight-bolder: bolder; +$font-weight-bolder: 600; //Border Radius diff --git a/src/ux-components/list-button/list-button.vue b/src/ux-components/list-button/list-button.vue index 2c22bc70..24a46018 100644 --- a/src/ux-components/list-button/list-button.vue +++ b/src/ux-components/list-button/list-button.vue @@ -85,7 +85,7 @@ export default { color: $black; font-weight: 500; background: #e7f1f6; - border-color: #0070d1; + border-color: $heritage-blue-primary; } &:checked + .list-button-content p, &:checked + .list-button-content span { diff --git a/src/ux-components/text-link/text-link.vue b/src/ux-components/text-link/text-link.vue index 31f989c9..7b65c45e 100644 --- a/src/ux-components/text-link/text-link.vue +++ b/src/ux-components/text-link/text-link.vue @@ -62,7 +62,7 @@ export default { diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index deddc2a1..5fe675da 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -77,6 +77,7 @@ @updated-mobile-ctu="setCtuForMobile" /> 0) { + let foundMatch = false; + if(this.selectedProvider && this.selectedProvider.providerNumber) { + const matchedProvider = providers.shopProviders.find( + (provider) => provider.providerNumber === this.selectedProvider.providerNumber + ); + if (matchedProvider) { + foundMatch = true; + this.selectedProvider = matchedProvider; + } + } + if(providers.shopProviders.length > 0 && !foundMatch) { this.selectedProvider = providers.shopProviders[0]; } } diff --git a/src/layouts/service-location/service-zip-question/service-zip-question.vue b/src/layouts/service-location/service-zip-question/service-zip-question.vue index 478ab789..dc5224a3 100644 --- a/src/layouts/service-location/service-zip-question/service-zip-question.vue +++ b/src/layouts/service-location/service-zip-question/service-zip-question.vue @@ -1,14 +1,13 @@ @@ -31,21 +30,32 @@ export default { }, // TODO: Correct prop def. props: { - modelValue: { - serviceZipCode: String - }, + modelValue: String, cmsWidgetName: String }, + data() { + return { + internalZipcode: this.modelValue + } + }, emits: ['update:modelValue'], - computed: { - value: { - get() { - return this.modelValue; - }, - set(newValue) { - this.$emit('update:modelValue', newValue); - } + methods: { + updateModelValue() { + this.$emit('update:modelValue', this.internalZipcode); + }, + }, + watch: { + modelValue(newValue) { + this.internalZipcode = newValue; } } }; + diff --git a/src/layouts/service-location/shop-address/shop-address.vue b/src/layouts/service-location/shop-address/shop-address.vue index 2989e0da..a44e6f62 100644 --- a/src/layouts/service-location/shop-address/shop-address.vue +++ b/src/layouts/service-location/shop-address/shop-address.vue @@ -17,11 +17,11 @@
{{ displayedShopName }} - {{ modelValue.distanceInMiles.toFixed(2) }} mi + {{ modelValue.distanceInMiles?.toFixed(2) }} mi
-
{{ toTitleCase(modelValue.address.streetAddress) }}
+
{{ toTitleCase(modelValue.address?.streetAddress) }}
- {{ toTitleCase(modelValue.address.city) }}, {{ modelValue.address.state }} {{ modelValue.address.zipCode }} + {{ toTitleCase(modelValue.address?.city) }}, {{ modelValue.address?.state }} {{ modelValue.address?.zipCode }}
+ + {{ serviceZipPrompt }} + null }, + serviceZipcode: String, cmsWidgetName: String, validationRules: String, isDisplayed: Boolean, @@ -109,13 +113,13 @@ export default { toTitleCase, serviceZipCodeTextInputId: '', displayInvalidZipAlert: false, - internalZipcode: this.modelValue.address.zipCode, + internalZipcode: this.serviceZipcode, internalProviderNumber: this.modelValue.providerNumber, textboxQuestionWidgetName: 'ChangeLocationZipQuestionWidget', alertInvalidZipWidgetName: 'AlertInvalidZipWidget', shopListButton: markRaw(shopListButton), searchRadiusInMiles: 25, - nearbyShops: this.getNearbyShops(25) + nearbyShops: [] }; }, emits: ['update:modelValue'], @@ -150,18 +154,37 @@ export default { const formattedEndDate = endDate.toISOString().split('T')[0]; return { - displayAvailabilityIndicators: true, + displayAvailabilityIndicators: false, availabilityRatingCallback: getAvailabilityRating, startDate: formattedStartDate, endDate: formattedEndDate, shopAppointmentType: this.selectedAppointmentType }; + }, + serviceZipPrompt() { + return this.getCmsContent(this.modalWidgetName, 'BodyText2'); + }, + nearbyShopsData() { + return this.nearbyShops.map((shopProvider) => { + const streetAddress = toTitleCase(shopProvider.address.streetAddress); + const city = toTitleCase(shopProvider.address.city); + const { state } = shopProvider.address; + const { zipCode } = shopProvider.address; + const distanceInMiles = shopProvider.distanceInMiles.toFixed(2); + + return { + buttonLabel: city, + buttonLabelSubCopy: `${distanceInMiles} mi`, + buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`, + value: shopProvider.providerNumber + }; + }); } }, watch: { - internalZipcode(newZipcode) { + internalZipcode() { this.resetsOnZipInput(); - }, + } }, methods: { resetAlerts() { @@ -171,10 +194,6 @@ export default { this.resetAlerts(); this.nearbyShops = await this.getNearbyShops(this.searchRadiusInMiles); }, - focusOnZipInput() { - const input = document.getElementById(this.serviceZipCodeTextInputId); - input?.focus(); - }, openModal() { this.$refs[this.modalName].openModal(); }, @@ -185,39 +204,29 @@ export default { this.serviceZipCodeTextInputId = inputId; }, onModalOpened() { - this.internalZipcode = this.modelValue.address.zipCode; - this.internalProviderNumber = this.modelValue.providerNumber; - this.focusOnZipInput(); + this.internalZipcode = this.serviceZipcode; + this.resetsOnZipInput().then(() => { + this.internalProviderNumber = this.nearbyShops[0]?.providerNumber; + }); }, onModalClosed() { - this.internalZipcode = this.modelValue.address.zipCode; - this.internalProviderNumber = this.modelValue.providerNumber; - this.resetsOnZipInput(); + this.internalZipcode = this.serviceZipcode; + this.resetsOnZipInput().then(() => { + this.internalProviderNumber = this.nearbyShops[0]?.providerNumber; + }); }, async updateSelectedProvider() { - // TODO: Do something with the zipcode? + if (this.internalProviderNumber !== this.modelValue.providerNumber) { + const selectedShop = this.nearbyShops.find(shop => shop.providerNumber === this.internalProviderNumber); + if (selectedShop) { + this.$emit('update:modelValue', selectedShop); + } + } + this.closeModal(); }, async getNearbyShops(radiusInMiles) { const result = await useMainStore().getProviders(this.internalZipcode, radiusInMiles); - - const mappedData = result.data.shopProviders.map((shopProvider) => { - const streetAddress = toTitleCase(shopProvider.address.streetAddress); - const city = toTitleCase(shopProvider.address.city); - const { state } = shopProvider.address; - const { zipCode } = shopProvider.address; - const distanceInMiles = Math.round(shopProvider.distanceInMiles * 2) / 2; - - return { - buttonLabel: city, - buttonLabelSubCopy: `${distanceInMiles} mi`, - buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`, - value: shopProvider.providerNumber - }; - }); - - console.log('Internal provider number after getting shops:', this.internalProviderNumber); - - return mappedData; + return result.data.shopProviders; } } }; @@ -227,6 +236,7 @@ export default { @import "@/styles/ux-variables-svg-strings.scss"; .shop-address { .address-header { + color: $black; font-weight: 600; margin-bottom: 0.625rem; } @@ -242,6 +252,14 @@ export default { :deep(.modal-title) { font-weight: 400; display: block; + width: fit-content; + } + .radioQuestion { + margin-bottom: .625rem; + } + .service-zip-prompt { + color: $black; + font-weight: 600; } } diff --git a/src/store/index.js b/src/store/index.js index ef1b7f52..00995f29 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1798,6 +1798,7 @@ export const useMainStore = defineStore({ this.order.vehicle.registration.lastName = registrationInfo?.lastName; }, updateServiceLocation(serviceLocationInfo) { + console.log('Updating service location info:', serviceLocationInfo); this.order.serviceLocation.address = serviceLocationInfo.address; this.order.serviceLocation.address2 = serviceLocationInfo.address2; this.order.serviceLocation.city = serviceLocationInfo.city; @@ -2707,6 +2708,7 @@ export const useMainStore = defineStore({ }, saveServiceLocation(serviceLocationInfo) { + console.log('Saving service location info:', serviceLocationInfo); if (this.order.serviceLocation) { if ( serviceLocationInfo.zipCode !== this.order.serviceLocation.zipCode @@ -2717,6 +2719,7 @@ export const useMainStore = defineStore({ || serviceLocationInfo.appointmentType !== this.order.serviceLocation.appointmentType ) { + console.log('Service location info has changed, resetting dependent state.'); this.resetSchedule(); } } diff --git a/src/styles/ux-variables.scss b/src/styles/ux-variables.scss index 56bd5bad..206716b6 100644 --- a/src/styles/ux-variables.scss +++ b/src/styles/ux-variables.scss @@ -70,6 +70,10 @@ $orange: #fd7e14; $teal: #20c997; $cyan: #0dcaf0; +//Heritage +$heritage-blue-primary: #0070D1; +$heritage-blue-secondary: #167cac; + // Darker gray $darker-gray: #525656; @@ -145,7 +149,7 @@ $font-weight-lighter: lighter; $font-weight-light: 300; $font-weight-normal: 400; $font-weight-bold: 500; -$font-weight-bolder: 600; +$font-weight-bolder: bolder; //Border Radius @@ -217,8 +221,4 @@ $enable-important-utilities: false; $letter-spacing-primary: 0.03em; // Borders $border-input: 1px solid rgba(179, 180, 181); -$border-input-focus: 2.5px solid $blue; - -//Heritage -$heritage-blue-primary: #0070D1; -$heritage-blue-secondary: #167cac; \ No newline at end of file +$border-input-focus: 2.5px solid $heritage-blue-primary; diff --git a/src/ux-components/list-button/list-button.vue b/src/ux-components/list-button/list-button.vue index 942d2154..c3566b68 100644 --- a/src/ux-components/list-button/list-button.vue +++ b/src/ux-components/list-button/list-button.vue @@ -87,15 +87,18 @@ $heritage-checked-border-color: #0070d1; &:checked + .list-button-content { background: $heritage-checked-background-color; border-color: $heritage-checked-border-color; - box-shadow: 0 0 0 1px $blue; &:not(.has-sub-copy) { font-weight: 500; + color: $black; } } &:checked + .list-button-content span:nth-child(2) { font-weight: 400; color: $gray-600; } + &:focus:checked + .list-button-content { + border-width: 2.5px; + } } } .list-button-content { @@ -110,9 +113,12 @@ $heritage-checked-border-color: #0070d1; width: 100%; outline: none; margin-bottom: .625rem; + height: 4.375rem; &:not(.has-sub-copy) { font-weight: 400; + height: 2.8125rem; + color: $darker-gray; } span { From bcc156ec293beff8b172ec9ffcede75a8899d9a0 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Fri, 9 Jan 2026 16:00:54 -0500 Subject: [PATCH 05/49] Add search radius to change location modal + related style updates --- src/constants/button-variants.js | 9 ---- src/constants/component-variants.js | 15 ++++++ src/constants/error-messages.js | 4 +- .../dropdown-question/dropdown-question.vue | 39 ++++++++++++-- src/digital-components/modal/modal.vue | 10 ++-- .../textbox-question/textbox-question.vue | 14 ++++- .../policy-vehicles/policy-vehicles.vue | 2 +- .../service-location/service-location.vue | 6 --- .../service-zip-question.spec.js | 1 - .../service-zip-question.vue | 2 +- .../shop-address/shop-address.vue | 54 +++++++++++++------ .../button-main/button-main.spec.js | 2 +- src/ux-components/button-main/button-main.vue | 2 +- 13 files changed, 113 insertions(+), 47 deletions(-) delete mode 100644 src/constants/button-variants.js create mode 100644 src/constants/component-variants.js diff --git a/src/constants/button-variants.js b/src/constants/button-variants.js deleted file mode 100644 index cf73718a..00000000 --- a/src/constants/button-variants.js +++ /dev/null @@ -1,9 +0,0 @@ -const buttonVariants = Object.freeze({ - primary: 'primary', - secondary: 'secondary', - success: 'success', - link: 'link', - navigation: 'navigation' -}); - -export default buttonVariants; diff --git a/src/constants/component-variants.js b/src/constants/component-variants.js new file mode 100644 index 00000000..7fd84311 --- /dev/null +++ b/src/constants/component-variants.js @@ -0,0 +1,15 @@ +export const buttonVariants = Object.freeze({ + primary: 'primary', + secondary: 'secondary', + success: 'success', + link: 'link', + navigation: 'navigation' +}); +export const dropdownVariants = Object.freeze({ + primary: 'primary', + compact: 'compact' +}); +export const modalPositions = Object.freeze({ + center: 'center', + edge: 'edge' +}); diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index 90493221..65acc9ae 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -23,8 +23,8 @@ const errorMessages = Object.freeze({ LAST_NAME_REQUIRED: 'Please enter your last name', EMAIL_ADDRESS_REQUIRED: 'Email is required.', EMAIL_ADDRESS_FORMAT: 'Please enter a valid email address.', - SERVICE_ZIP_REQUIRED: 'Please enter your service ZIP', - SERVICE_ZIP_FORMAT: 'Please enter a valid service ZIP', + SERVICE_ZIP_REQUIRED: 'ZIP code is required', + SERVICE_ZIP_FORMAT: 'Invalid ZIP, please enter a new ZIP (5 characters)', VIN_REQUIRED: 'Please enter your VIN', VIN_FORMAT: // eslint-disable-next-line max-len diff --git a/src/digital-components/dropdown-question/dropdown-question.vue b/src/digital-components/dropdown-question/dropdown-question.vue index 69b8a530..536ed4c9 100644 --- a/src/digital-components/dropdown-question/dropdown-question.vue +++ b/src/digital-components/dropdown-question/dropdown-question.vue @@ -2,8 +2,9 @@ -
{{ toTitleCase(modelValue.address?.streetAddress) }}
+
{{ getProviderAddress(modelValue) }}
- {{ toTitleCase(modelValue.address?.city) }}, {{ modelValue.address?.state }} {{ modelValue.address?.zipCode }} + {{ getProviderCityZipState(modelValue) }}
+ { - const streetAddress = toTitleCase(shopProvider.address.streetAddress); const city = toTitleCase(shopProvider.address.city); - const { state } = shopProvider.address; - const { zipCode } = shopProvider.address; const distanceInMiles = shopProvider.distanceInMiles.toFixed(2); return { buttonLabel: city, buttonLabelSubCopy: `${distanceInMiles} mi`, - buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`, + buttonBodyCopy: this.getFullProviderAddress(shopProvider), value: shopProvider.providerNumber }; }); @@ -200,11 +206,18 @@ export default { optionsObj[option.Name] = option.Text; }); return optionsObj; - } + }, + providerAddresses() { + return this.nearbyShops?.map((provider) => ({ + title: toTitleCase(provider.companyName), + fullAddress: this.getFullProviderAddress(provider), + addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)] + })) ?? []; + }, }, watch: { - internalZipcode() { - this.refreshShops(); + async internalZipcode() { + await this.resetsOnZipInput(); }, async searchRadiusInMiles() { this.nearbyShops = await this.getNearbyShops(this.searchRadiusInMiles); @@ -230,6 +243,7 @@ export default { this.resetsOnZipInput().then(() => { this.internalProviderNumber = this.nearbyShops[0]?.providerNumber; }); + this.forceServiceZipRerender(); }, onModalClosed() { this.internalZipcode = this.serviceZipcode; @@ -249,6 +263,42 @@ export default { async getNearbyShops(radiusInMiles) { const result = await useMainStore().getProviders(this.internalZipcode, radiusInMiles); return result.data.shopProviders; + }, + getFullProviderAddress(provider) { + const addressLine1 = this.getProviderAddress(provider); + const addressLine2 = this.getProviderCityZipState(provider); + const joinString = + addressLine1.length > 0 && addressLine2.length > 0 ? ', ' : ''; + return [addressLine1, addressLine2].join(joinString); + }, + getProviderAddress(provider) { + return toTitleCase(provider?.address?.streetAddress); + }, + getProviderCityZipState(provider) { + const city = toTitleCase(provider?.address?.city); + const state = provider?.address?.state ?? ''; + const zipCode = provider?.address?.zipCode ?? ''; + let addressLine2 = ''; + if (city) { + addressLine2 += city; + if (state || zipCode) { + addressLine2 += state ? ', ' : ' '; + } + } + if (state) { + addressLine2 += state; + addressLine2 += zipCode ? ' ' : ''; + } + if (zipCode) { + addressLine2 += zipCode; + } + return addressLine2; + }, + forceServiceZipRerender() { + this.renderServiceZip = false; + this.$nextTick(() => { + this.renderServiceZip = true; + }); } } }; @@ -283,5 +333,8 @@ export default { color: $black; font-weight: 600; } + :deep(#map) { + height: 27rem; + } } From 21e9127b5062d1c0f7d81a1179c49b7c5acab57f Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Tue, 13 Jan 2026 12:20:05 -0500 Subject: [PATCH 07/49] Fix availability indicators for shop address --- .../shop-list-button/shop-list-button.vue | 44 ++++++++++++++----- .../service-location/service-location.vue | 2 +- .../shop-address/shop-address.vue | 4 +- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/iss-components/shop-list-button/shop-list-button.vue b/src/iss-components/shop-list-button/shop-list-button.vue index 44812a90..42b89ba3 100644 --- a/src/iss-components/shop-list-button/shop-list-button.vue +++ b/src/iss-components/shop-list-button/shop-list-button.vue @@ -10,6 +10,7 @@ :aria-label="buttonLabel" class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4">
+
{{ buttonLabelSubCopy }} -
+
+ v-if="displayAvailabilityIndicators" + id="availabilityIndicatorBlock" + class="availability-indicator rounded-pill" + :class="availabilityRatingClass">
+ id="availabilityIndicator" + class="d-flex align-items-center"> +
+
+ {{ badgeText }}
- {{ badgeText }}
@@ -157,11 +160,23 @@ $heritage-checked-border-color: #0070d1; border-left: 1px solid $heritage-border-color; } + .availability-indicator-spacer { + width: 8rem; + margin-right: auto; + } + + .availability-indicator-container { + display: flex; + align-items: center; + justify-content: flex-end; + margin-left: auto; + width: 8rem; + } + .availability-indicator { background-repeat: no-repeat; display: flex; align-items: center; - margin-left: auto; padding: 0.125rem 0.5rem; .availability-badge { @@ -179,6 +194,11 @@ $heritage-checked-border-color: #0070d1; &.orange { background-image: url($svg-shop-list-button-orange-availability); } + + &.gray { + background-image: url(~@/assets/img/heritage-loader-blue.gif); + background-size: contain; + } } .button-auxillary-copy { box-sizing: border-box; diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index b7b5fcee..92f3ea7e 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -79,7 +79,7 @@ v-model="selectedProvider" :serviceZipcode="zipCode" :isDisplayed="isInshop" - :selectAppointmentType="selectedAppointmentType" + :selectedAppointmentType="selectedAppointmentType" modalWidgetName="ChangeLocationModalWidget" cmsWidgetName="ShopAddressWidget" /> Date: Thu, 15 Jan 2026 13:18:12 -0500 Subject: [PATCH 08/49] Some updates for validation on zip entry/shop search --- src/constants/error-messages.js | 5 + .../button-question/button-question.vue | 5 + src/digital-components/modal/modal.vue | 6 +- .../text-block/text-block.vue | 9 +- .../textbox-question/textbox-question.vue | 10 +- src/iss-components/google-map/google-map.vue | 2 +- .../shop-list-button.spec.js.snap | 4 +- .../appointment-type-question.vue | 21 +- .../service-location/service-location.vue | 223 ++++++------- .../service-zip-question.spec.js | 8 +- .../service-zip-question.vue | 32 +- .../shop-address/shop-address.vue | 124 +++++--- .../shop-question/shop-question.vue | 294 ------------------ src/store/index.js | 3 - src/styles/common-typography-styles.scss | 18 -- src/styles/ux-variables.scss | 3 +- 16 files changed, 255 insertions(+), 512 deletions(-) delete mode 100644 src/layouts/service-location/shop-question/shop-question.vue diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index 65acc9ae..ace5e564 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -25,6 +25,11 @@ const errorMessages = Object.freeze({ EMAIL_ADDRESS_FORMAT: 'Please enter a valid email address.', SERVICE_ZIP_REQUIRED: 'ZIP code is required', SERVICE_ZIP_FORMAT: 'Invalid ZIP, please enter a new ZIP (5 characters)', + MOBILE_SERVICE_ZIP_FORMAT: 'Invalid ZIP code', + NO_SERVICE_IN_ZIP: (zip) => `We're sorry, but we don't offer service in ${zip} at this time.`, + PROVIDER_REQUIRED: 'Please select a provider.', + INVALID_ZIP: 'The ZIP you entered was invalid. Please enter a valid ZIP.', + ZIP_CODE_NOT_SERVICED_FOR_VEHICLE: 'We do not currently offer glass service for your vehicle in this ZIP code. Please try another ZIP code.', VIN_REQUIRED: 'Please enter your VIN', VIN_FORMAT: // eslint-disable-next-line max-len diff --git a/src/digital-components/button-question/button-question.vue b/src/digital-components/button-question/button-question.vue index 5c380612..da7eb5c7 100644 --- a/src/digital-components/button-question/button-question.vue +++ b/src/digital-components/button-question/button-question.vue @@ -294,6 +294,11 @@ export default { this.resetField({ value: newValue }); + }, + answers() { + this.resetField({ + value: this.modelValue + }); } }, beforeMount() { diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 3875cf0a..8f952d6b 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -86,6 +86,10 @@ export default { modalPosition: { type: String, default: modalPositions.edge + }, + allowInvalidSubmit: { + type: Boolean, + default: false } }, emits: ['footer-button-event', 'isModalOpened'], @@ -123,7 +127,7 @@ export default { methods: { async validateAndEmit() { const validationResult = await this.validate(); - if (validationResult.valid) { + if (validationResult.valid || this.allowInvalidSubmit) { this.$emit('footer-button-event'); } }, diff --git a/src/digital-components/text-block/text-block.vue b/src/digital-components/text-block/text-block.vue index f6d0d591..f6db4887 100644 --- a/src/digital-components/text-block/text-block.vue +++ b/src/digital-components/text-block/text-block.vue @@ -51,7 +51,7 @@ export default { props: { customText: String, // used to allow the insert of token values into textblock justifyText: String, // left, right, center - typeStyle: String, // h1-h6, body, small, label, caption + typeStyle: String, // h1-h6, body, small, label, caption, disclaimer // (see Figma or Confluence documentation) fontWeight: String, // bold=500, default is 400 cmsWidgetName: String, @@ -109,5 +109,12 @@ export default { &.dark { color: $black; } + &.disclaimer { + color: $lighter-gray; + font-weight: $font-weight-light; + font-size: .8125rem; + font-style: italic; + margin-top: .625rem; + } } diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 7992abb7..028617e7 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -250,8 +250,10 @@ export default { this.$emit('click-event'); } }, - clickedTextButton() { - if (this.meta.valid) { + async clickedTextButton() { + const result = await validate(this.value, this.validationRules); + if (result.valid) { + this.handleChange(this.value); this.$emit('click-event'); } } @@ -378,8 +380,8 @@ input::-webkit-date-and-time-value { .form-control { border: $border-input; border-radius: $border-radius; - min-height: 3rem; - max-height: 3rem; + min-height: 2.8125rem; + max-height: 2.8125rem; padding: 0.75rem 1rem; letter-spacing: inherit; box-shadow: $box-shadow-input; diff --git a/src/iss-components/google-map/google-map.vue b/src/iss-components/google-map/google-map.vue index 4f2fa023..686cf5ec 100644 --- a/src/iss-components/google-map/google-map.vue +++ b/src/iss-components/google-map/google-map.vue @@ -55,7 +55,7 @@ export default { const { AdvancedMarkerElement, PinElement } = await window.google.maps.importLibrary('marker'); markers?.forEach((marker, index) => { const pinElement = new PinElement({ - glyph: String.fromCharCode('A'.charCodeAt(0) + index), + glyphText: String.fromCharCode('A'.charCodeAt(0) + index), glyphColor: '#000000', borderColor: '#000000' }); diff --git a/src/iss-components/shop-list-button/__snapshots__/shop-list-button.spec.js.snap b/src/iss-components/shop-list-button/__snapshots__/shop-list-button.spec.js.snap index 200d67d6..209c7610 100644 --- a/src/iss-components/shop-list-button/__snapshots__/shop-list-button.spec.js.snap +++ b/src/iss-components/shop-list-button/__snapshots__/shop-list-button.spec.js.snap @@ -2,13 +2,13 @@ exports[`Shop list button should render correctly with all relevant props 1`] = ` - + `; exports[`Shop list button should render correctly with required props 1`] = ` - + `; 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 index 41c0353d..32dda198 100644 --- a/src/layouts/service-location/appointment-type-question/appointment-type-question.vue +++ b/src/layouts/service-location/appointment-type-question/appointment-type-question.vue @@ -57,16 +57,12 @@ export default { return retCms; }, answersToDisplay() { - const shouldShowMobile = this.isServiceableMobile && this.isItacOrNoComp; - const shouldShowMobileNotITACNotNoComp = this.isServiceableMobile && !this.isItacOrNoComp; + const shouldShowMobile = this.isServiceableMobile; const shouldShowInshop = this.isServiceableInshop; - const shouldShowDropoff = this.isServiceableInshop && !useMainStore().damage.isRepair; return this.answersFromCms ? this.answersFromCms.filter((answer) => ( (answer.Name === AppointmentTypeStrings.IN_SHOP && shouldShowInshop) || (answer.Name === AppointmentTypeStrings.MOBILE && shouldShowMobile) - || (answer.Name === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP && shouldShowMobileNotITACNotNoComp) - || (answer.Name === AppointmentTypeStrings.DROP_OFF && shouldShowDropoff) )) : []; }, @@ -97,14 +93,9 @@ export default { // If there is only one option to display and that option is 'Mobile' then select it if ( newValue.length === 1 - && newValue.findIndex((answer) => (answer.Name === AppointmentTypeStrings.MOBILE - || answer.Name === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP)) !== -1 + && newValue.findIndex((answer) => (answer.Name === AppointmentTypeStrings.MOBILE)) !== -1 ) { - if (this.isItacOrNoComp) { - this.selectedValues = AppointmentTypeStrings.MOBILE; - } else { - this.selectedValues = AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; - } + this.selectedValues = AppointmentTypeStrings.MOBILE; } }, immediate: true @@ -112,11 +103,7 @@ export default { isMobileOnly: { handler(newValue) { if (newValue) { - if (this.isItacOrNoComp) { - this.selectedValues = AppointmentTypeStrings.MOBILE; - } else { - this.selectedValues = AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP; - } + this.selectedValues = AppointmentTypeStrings.MOBILE; } } } diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 92f3ea7e..e38bc1cd 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -62,26 +62,39 @@ cmsWidgetName="AppointmentTypeQuestionWidget" validationRules="option-required" />
- + cmsWidgetName="ShopAddressWidget" + @zip-updated="handleInShopZipUpdated" /> +
+ +
+ {{ mobileZipError }} +
+ +
{ - 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)); +import shopAddress from '@/layouts/service-location/shop-address/shop-address.vue'; +import serviceZipQuestion from '@/layouts/service-location/service-zip-question/service-zip-question.vue'; +import widgetFields from '@/constants/cms-widget-fields'; const RECAL_MODAL_REF_NAME = 'RecalModal'; const SITE_FOOTER_REF_NAME = 'siteFooter'; @@ -148,15 +149,16 @@ export default { name: 'service-location', components: { alert, + textBlock, appointmentTypeQuestion, contentGroupModal, - mobileLocationModalQuestions, siteFooter, siteHeader, siteSubHeader, // eslint-disable-next-line vue/no-reserved-component-names Form, - shopAddress + shopAddress, + serviceZipQuestion }, mixins: [baseFormMixin], async beforeRouteEnter(to, from, next) { @@ -232,8 +234,12 @@ export default { mobileProviderNumber: null, zipContainsMilitaryBase: false, zipCodeCtu: null, + mobileZipCode: '', + mobileZipError: '', + showMobileOption: false, RECAL_MODAL_REF_NAME, - SITE_FOOTER_REF_NAME + SITE_FOOTER_REF_NAME, + errorMessages }; }, computed: { @@ -246,35 +252,6 @@ export default { answersFromCms() { return this.getCmsContent('ServiceTypeQuestionWidget', 'Answers'); }, - mobileLocationQuestions: { - get() { - return { - addressQuestions: { - streetAddress: this.streetAddress, - streetAddress2: this.streetAddress2, - city: this.city, - state: this.state, - zipCode: this.zipCode - }, - isVehicleProtected: this.isVehicleProtected - }; - }, - set(newValue) { - this.streetAddress = newValue.addressQuestions.streetAddress; - this.streetAddress2 = newValue.addressQuestions.streetAddress2; - 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.isMobile) { - this.selectedAppointmentType = null; - } - this.selectedProvider = null; - } - } - }, isServiceableMobile() { if (this.isRecalibrationServiceableMobile !== null) { return ( @@ -301,15 +278,10 @@ export default { ); }, isAppointmentTypeDisplayed() { - return this.zipCode && !this.displayNoShopsAlert; + return this.zipCode && !this.displayNoShopsAlert && this.showMobileOption; }, isMobile() { - return ( - this.selectedAppointmentType - === AppointmentTypeStrings.MOBILE - || this.selectedAppointmentType - === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP - ); + return this.selectedAppointmentType === AppointmentTypeStrings.MOBILE }, requiresInshopRecalibration() { // Specifically check for isRecalibrationServiceableMobile === false, not null or true. @@ -341,6 +313,9 @@ export default { displayServiceableMobileOnly() { return this.isServiceableMobile && !this.isServiceableInshop; }, + displayMobileFeeDisclaimer() { + return this.mainStore.isNoComp || this.mainStore.isITAC; + }, navigateBackScenario() { const { isNoComp, isITAC } = useMainStore(); return isNoComp || isITAC @@ -349,7 +324,10 @@ export default { }, isBigTruck() { return this.mainStore.order.vehicle.isBigTruck; - } + }, + mobileZipPlaceholder() { + return this.getCmsContent('MobileZipPlaceHolderWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT); + }, }, methods: { arePagePrerequisitesValid() { @@ -445,6 +423,7 @@ export default { if (serviceabilityDetails) { this.setServiceabilityDetails(serviceabilityDetails); + this.showMobileOption = this.isServiceableMobile; } if (mobileFeePart) { @@ -503,6 +482,65 @@ export default { serviceabilityDetails.isGlassServiceableMobile; this.isRecalibrationServiceableMobile = serviceabilityDetails.isRecalibrationServiceableMobile; + }, + async updateMobileZip() { + this.mobileZipError = ''; + + const zipCodeData = await getMobileZipCodeData(this.mobileZipCode); + + if (!zipCodeData.isValid) { + this.mobileZipError = errorMessages.INVALID_ZIP; + } else if (!zipCodeData.isServiceable) { + this.mobileZipError = errorMessages.NO_SERVICE_IN_ZIP(this.mobileZipCode); + } else { + this.zipCode = this.mobileZipCode; + this.setCtuForMobile(zipCodeData.zipCodeCtu); + this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase); + + const serviceabilityDetailsPromise = getServiceabilityDetails(this.mobileZipCode); + serviceabilityDetailsPromise.then((result) => { + const details = result.data; + if (details) { + this.setServiceabilityDetails(details); + } + }); + + const providersPromise = useMainStore().getProviders(this.mobileZipCode); + providersPromise.then((result) => { + const providers = result.data; + if (providers) { + this.setMobileProviderNumber(providers.mobileProviderNumber); + if(providers.shopProviders.length > 0) { + this.selectedProvider = providers.shopProviders[0]; + } + } + }); + } + }, + async handleInShopZipUpdated(newZip) { + this.zipCode = newZip; + const zipCodeData = await getZipCodeData(this.zipCode); + this.setCtuForMobile(zipCodeData.zipCodeCtu); + this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase); + + const serviceabilityDetailsPromise = getServiceabilityDetails(this.zipCode); + serviceabilityDetailsPromise.then((result) => { + const details = result.data; + if (details) { + this.setServiceabilityDetails(details); + this.showMobileOption = this.isServiceableMobile; + } + }); + } + }, + watch: { + mobileZipCode(newZip) { + if(newZip !== '') { + this.updateMobileZip(); + } + }, + selectedAppointmentType() { + this.mobileZipCode = ''; } } }; @@ -510,7 +548,6 @@ export default { diff --git a/src/layouts/service-location/shop-address/shop-address.vue b/src/layouts/service-location/shop-address/shop-address.vue index ce3e3deb..2417a52a 100644 --- a/src/layouts/service-location/shop-address/shop-address.vue +++ b/src/layouts/service-location/shop-address/shop-address.vue @@ -6,13 +6,6 @@ v-if="isDisplayed" class="shop-address" aria-live="polite"> -
{{ questionText }}
@@ -32,9 +25,9 @@ :ref="modalName" :headerText="modalHeaderText" :onModalOpenedCallback="onModalOpened" - :onModalClosedCallback="onModalClosed" :footerButtonText="modalFooterText" :modalPosition="modalPositions.center" + :allowInvalidSubmit="true" @footerButtonEvent="updateSelectedProvider"> - +
+ {{ errorMessage }} +
@@ -96,11 +90,17 @@ import googleMap from '@/iss-components/google-map/google-map.vue'; import baseMixin from '@/mixins/base-mixin.js'; import { toTitleCase } from '@/helpers/text-helper.js'; import { markRaw } from 'vue'; -import { getServiceabilityDetails, getZipCodeData,getAvailabilityRating } from '@/helpers/service-location-helper'; +import { getAvailabilityRating } from '@/helpers/service-location-helper'; import { useMainStore } from '@/store'; import widgetFields from '@/constants/cms-widget-fields'; import { dropdownVariants, modalPositions } from '@/constants/component-variants'; +import errorMessages from '@/constants/error-messages'; +import { defineRule } from 'vee-validate'; +import { required } from '@/helpers/validation-rules'; +defineRule('option-required', required(errorMessages.PROVIDER_REQUIRED)); + +const SERVICE_ZIP_QUESTION_REF_NAME = 'serviceZipCodeQuestion'; export default { name: 'shop-address', @@ -130,21 +130,21 @@ export default { return { toTitleCase, serviceZipCodeTextInputId: '', - displayInvalidZipAlert: false, internalZipcode: this.serviceZipcode, internalProviderNumber: this.modelValue.providerNumber, searchRadiusQuestionWidgetName: 'SearchRadiusQuestionWidget', textboxQuestionWidgetName: 'ChangeLocationZipQuestionWidget', - alertInvalidZipWidgetName: 'AlertInvalidZipWidget', shopListButton: markRaw(shopListButton), - searchRadiusInMiles: 100, + searchRadiusInMiles: "25", nearbyShops: [], modalPositions, dropdownVariants, - renderServiceZip: true + renderServiceZip: true, + errorMessage: '', + SERVICE_ZIP_QUESTION_REF_NAME }; }, - emits: ['update:modelValue'], + emits: ['update:modelValue', 'zip-updated'], computed: { questionText() { return this.getCmsContent(this.cmsWidgetName, widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT); @@ -199,12 +199,17 @@ export default { }; }); }, - searchRadiusOptions() { + searchRadiusArray() { const options = this.getCmsContent(this.searchRadiusQuestionWidgetName, widgetFields.INPUT_QUESTION_WIDGET.ANSWERS); + return options; + }, + searchRadiusOptions() { const optionsObj = {}; - options.forEach(option => { - optionsObj[option.Name] = option.Text; - }); + if(this.searchRadiusArray) { + this.searchRadiusArray.forEach(option => { + optionsObj[option.Name] = option.Text; + }); + } return optionsObj; }, providerAddresses() { @@ -217,19 +222,30 @@ export default { }, watch: { async internalZipcode() { - await this.resetsOnZipInput(); + const shopsUpdated = await this.updateShops(); + if (shopsUpdated) { + this.$refs[SERVICE_ZIP_QUESTION_REF_NAME].internalZipcode = ''; + } }, async searchRadiusInMiles() { - this.nearbyShops = await this.getNearbyShops(this.searchRadiusInMiles); + await this.updateShops(); + }, + nearbyShops(newShops) { + if (!newShops.find(shop => shop.providerNumber === this.internalProviderNumber)) { + this.internalProviderNumber = ''; + } } }, methods: { - resetAlerts() { - this.displayInvalidZipAlert = false; - }, - async resetsOnZipInput() { - this.resetAlerts(); - this.nearbyShops = await this.getNearbyShops(this.searchRadiusInMiles); + async updateShops() { + this.errorMessage = ''; + const result = await this.getNearbyShops(this.searchRadiusInMiles); + if (result.length === 0) { + this.errorMessage = errorMessages.ZIP_CODE_NOT_SERVICED_FOR_VEHICLE; + } + else { + this.nearbyShops = await this.getNearbyShops(this.searchRadiusInMiles); + } }, openModal() { this.$refs[this.modalName].openModal(); @@ -239,26 +255,19 @@ export default { }, onModalOpened() { this.internalZipcode = this.serviceZipcode; - this.searchRadiusInMiles = 25; - this.resetsOnZipInput().then(() => { + this.searchRadiusInMiles = "25"; + this.updateShops().then(() => { this.internalProviderNumber = this.nearbyShops[0]?.providerNumber; }); this.forceServiceZipRerender(); }, - onModalClosed() { - this.internalZipcode = this.serviceZipcode; - this.resetsOnZipInput().then(() => { - this.internalProviderNumber = this.nearbyShops[0]?.providerNumber; - }); - }, async updateSelectedProvider() { - if (this.internalProviderNumber !== this.modelValue.providerNumber) { - const selectedShop = this.nearbyShops.find(shop => shop.providerNumber === this.internalProviderNumber); - if (selectedShop) { - this.$emit('update:modelValue', selectedShop); - } + const selectedShop = this.nearbyShops.find(shop => shop.providerNumber === this.internalProviderNumber); + if (selectedShop) { + this.$emit('update:modelValue', selectedShop); + this.$emit('zip-updated', this.internalZipcode); + this.closeModal(); } - this.closeModal(); }, async getNearbyShops(radiusInMiles) { const result = await useMainStore().getProviders(this.internalZipcode, radiusInMiles); @@ -336,5 +345,22 @@ export default { :deep(#map) { height: 27rem; } + :deep(.textbox-question) { + &.has-error { + input.form-control { + border: $border-input; + &:focus { + border: $border-input-focus; + } + } + } + .form-label { + font-weight: $font-weight-normal; + color: $darker-gray; + } + .btn-primary { + margin-bottom: 1.25rem; + } + } } diff --git a/src/layouts/service-location/shop-question/shop-question.vue b/src/layouts/service-location/shop-question/shop-question.vue deleted file mode 100644 index fdbbdd79..00000000 --- a/src/layouts/service-location/shop-question/shop-question.vue +++ /dev/null @@ -1,294 +0,0 @@ - - - - - diff --git a/src/store/index.js b/src/store/index.js index 00995f29..ef1b7f52 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1798,7 +1798,6 @@ export const useMainStore = defineStore({ this.order.vehicle.registration.lastName = registrationInfo?.lastName; }, updateServiceLocation(serviceLocationInfo) { - console.log('Updating service location info:', serviceLocationInfo); this.order.serviceLocation.address = serviceLocationInfo.address; this.order.serviceLocation.address2 = serviceLocationInfo.address2; this.order.serviceLocation.city = serviceLocationInfo.city; @@ -2708,7 +2707,6 @@ export const useMainStore = defineStore({ }, saveServiceLocation(serviceLocationInfo) { - console.log('Saving service location info:', serviceLocationInfo); if (this.order.serviceLocation) { if ( serviceLocationInfo.zipCode !== this.order.serviceLocation.zipCode @@ -2719,7 +2717,6 @@ export const useMainStore = defineStore({ || serviceLocationInfo.appointmentType !== this.order.serviceLocation.appointmentType ) { - console.log('Service location info has changed, resetting dependent state.'); this.resetSchedule(); } } diff --git a/src/styles/common-typography-styles.scss b/src/styles/common-typography-styles.scss index cdaf2ebf..a745b5d8 100644 --- a/src/styles/common-typography-styles.scss +++ b/src/styles/common-typography-styles.scss @@ -115,21 +115,3 @@ caption, font-weight: 800; font-style: normal; } - -@font-face { - font-family: "Urbanist"; - src: - url("@/assets/fonts/Urbanist-MediumItalic.woff2") format("woff2"), - url("@/assets/fonts/Urbanist-MediumItalic.woff") format("woff"); - font-weight: 500; - font-style: italic; -} - -@font-face { - font-family: "Urbanist"; - src: - url("@/assets/fonts/Urbanist-BoldItalic.woff2") format("woff2"), - url("@/assets/fonts/Urbanist-BoldItalic.woff") format("woff"); - font-weight: 700; - font-style: italic; -} \ No newline at end of file diff --git a/src/styles/ux-variables.scss b/src/styles/ux-variables.scss index 206716b6..b571d788 100644 --- a/src/styles/ux-variables.scss +++ b/src/styles/ux-variables.scss @@ -76,6 +76,7 @@ $heritage-blue-secondary: #167cac; // Darker gray $darker-gray: #525656; +$lighter-gray: #9aa1a3; // scss-docs-start colors-map $colors: ( @@ -220,5 +221,5 @@ $enable-important-utilities: false; // Letter Spacing $letter-spacing-primary: 0.03em; // Borders -$border-input: 1px solid rgba(179, 180, 181); +$border-input: 1px solid $gray-350; $border-input-focus: 2.5px solid $heritage-blue-primary; From 97c3fe522beacfe5b42904b82cb38a2ed88b04e8 Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Thu, 15 Jan 2026 14:48:14 -0500 Subject: [PATCH 09/49] Navigation changes for moving policy holder details page to after vehicle selection and forcing it to always display. --- src/router/router-constants/routing-table.js | 10 +++++----- src/router/router.spec.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index f0f93cff..e25d80cf 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -9,7 +9,7 @@ const routingTable = () => [ maps: [ { scenario: navigationScenarios.CLICKED_BACK, - destinationIssPageValue: issPageValues.POLICY_HOLDER_DETAILS + destinationIssPageValue: issPageValues.WELCOME_PAGE }, { scenario: navigationScenarios.CLICKED_FORWARD, @@ -26,7 +26,7 @@ const routingTable = () => [ maps: [ { scenario: navigationScenarios.CLICKED_BACK, - destinationIssPageValue: issPageValues.VEHICLE_SELECTION + destinationIssPageValue: issPageValues.POLICY_HOLDER_DETAILS }, { scenario: navigationScenarios.CLICKED_FORWARD_WITH_REPAIR, @@ -386,7 +386,7 @@ const routingTable = () => [ }, { scenario: navigationScenarios.CLICKED_FORWARD, - destinationIssPageValue: issPageValues.POLICY_HOLDER_DETAILS + destinationIssPageValue: issPageValues.VEHICLE_SELECTION }, { scenario: navigationScenarios.CLICKED_FORWARD_WITH_DUPLICATES, @@ -423,7 +423,7 @@ const routingTable = () => [ }, { scenario: navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED, - destinationIssPageValue: issPageValues.POLICY_HOLDER_DETAILS + destinationIssPageValue: issPageValues.VEHICLE_SELECTION }, { scenario: navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, @@ -473,7 +473,7 @@ const routingTable = () => [ }, { scenario: navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE, - destinationIssPageValue: issPageValues.VEHICLE_DAMAGE + destinationIssPageValue: issPageValues.POLICY_HOLDER_DETAILS }, { scenario: navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE, diff --git a/src/router/router.spec.js b/src/router/router.spec.js index c221dbf0..598e3912 100644 --- a/src/router/router.spec.js +++ b/src/router/router.spec.js @@ -19,7 +19,7 @@ describe('Router', () => { router.push = jest.fn(); router.navigate(scenario, currentRoute); - expect(router.push.mock.calls[0][0].query.issPage).toBe(issPageValues.POLICY_HOLDER_DETAILS); + expect(router.push.mock.calls[0][0].query.issPage).toBe(issPageValues.VEHICLE_SELECTION); }); it('Should set state as expected', () => { From b1ec2a298d3f0ff03b6d416410bfc86bb320beb2 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 15 Jan 2026 14:51:50 -0500 Subject: [PATCH 10/49] Auto expand shop search until shop is found --- .../shop-address/shop-address.vue | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/layouts/service-location/shop-address/shop-address.vue b/src/layouts/service-location/shop-address/shop-address.vue index 2417a52a..88fb545d 100644 --- a/src/layouts/service-location/shop-address/shop-address.vue +++ b/src/layouts/service-location/shop-address/shop-address.vue @@ -237,14 +237,21 @@ export default { } }, methods: { - async updateShops() { + async updateShops(autoExpand = false) { this.errorMessage = ''; - const result = await this.getNearbyShops(this.searchRadiusInMiles); + let result = await this.getNearbyShops(this.searchRadiusInMiles); + let currentSearchIndex = this.searchRadiusArray.findIndex(option => option.Name === this.searchRadiusInMiles); + while (autoExpand && result.length === 0 && currentSearchIndex < this.searchRadiusArray.length - 1) { + const newSearchRadius = this.searchRadiusArray[currentSearchIndex + 1].Name; + result = await this.getNearbyShops(newSearchRadius); + currentSearchIndex++; + } if (result.length === 0) { this.errorMessage = errorMessages.ZIP_CODE_NOT_SERVICED_FOR_VEHICLE; } else { - this.nearbyShops = await this.getNearbyShops(this.searchRadiusInMiles); + this.nearbyShops = result; + this.searchRadiusInMiles = this.searchRadiusArray[currentSearchIndex].Name; } }, openModal() { @@ -256,7 +263,8 @@ export default { onModalOpened() { this.internalZipcode = this.serviceZipcode; this.searchRadiusInMiles = "25"; - this.updateShops().then(() => { + this.nearbyShops = []; + this.updateShops(true).then(() => { this.internalProviderNumber = this.nearbyShops[0]?.providerNumber; }); this.forceServiceZipRerender(); @@ -308,7 +316,7 @@ export default { this.$nextTick(() => { this.renderServiceZip = true; }); - } + }, } }; From 253044d502feb4b6d69886ae442f5079ea6605da Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Fri, 16 Jan 2026 09:00:04 -0500 Subject: [PATCH 11/49] Some random tweaks, plus alert component updates --- src/assets/img/icons/alert-circle.svg | 3 + src/assets/img/icons/chevron-up.svg | 3 + src/helpers/service-location-helper.js | 1 + .../appointment-type-question.vue | 59 +---- .../service-location/service-location.vue | 99 ++++--- .../shop-address/shop-address.vue | 11 +- src/styles/ux-variables.scss | 3 + src/ux-components/alert/alert.vue | 249 ++++++++++++------ 8 files changed, 250 insertions(+), 178 deletions(-) create mode 100644 src/assets/img/icons/alert-circle.svg create mode 100644 src/assets/img/icons/chevron-up.svg diff --git a/src/assets/img/icons/alert-circle.svg b/src/assets/img/icons/alert-circle.svg new file mode 100644 index 00000000..904aefb9 --- /dev/null +++ b/src/assets/img/icons/alert-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/icons/chevron-up.svg b/src/assets/img/icons/chevron-up.svg new file mode 100644 index 00000000..f235d47f --- /dev/null +++ b/src/assets/img/icons/chevron-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/helpers/service-location-helper.js b/src/helpers/service-location-helper.js index 37127226..7e10ccd2 100644 --- a/src/helpers/service-location-helper.js +++ b/src/helpers/service-location-helper.js @@ -5,6 +5,7 @@ function processZipCodeResults(request) { containsMilitaryBase: serviceZipValidationResponse.containsMilitaryBase, isValid: serviceZipValidationResponse.isValid, isServiceable: serviceZipValidationResponse.isServiceable, + city: serviceZipValidationResponse.city, state: serviceZipValidationResponse.state, zipCodeCtu: serviceZipValidationResponse.zipCodeCtu })).catch(() => ({ 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 index 32dda198..d192a27f 100644 --- a/src/layouts/service-location/appointment-type-question/appointment-type-question.vue +++ b/src/layouts/service-location/appointment-type-question/appointment-type-question.vue @@ -3,15 +3,13 @@ name="fade" mode="out-in">
0 && this.isMobileFeeHidden) { - return retCms.map((x) => (x.Name === AppointmentTypeStrings.MOBILE ? { ...x, SubText: x.SubText.replace('*', '') } : x)); - } return retCms; }, - answersToDisplay() { - const shouldShowMobile = this.isServiceableMobile; - const shouldShowInshop = this.isServiceableInshop; - return this.answersFromCms - ? this.answersFromCms.filter((answer) => ( - (answer.Name === AppointmentTypeStrings.IN_SHOP && shouldShowInshop) - || (answer.Name === AppointmentTypeStrings.MOBILE && shouldShowMobile) - )) - : []; - }, selectedValues: { get() { return this.modelValue; @@ -73,46 +55,13 @@ export default { set(newValue) { this.$emit('update:modelValue', newValue); } - }, - isITAC() { - return useMainStore().isITAC; - }, - isItacOrNoComp() { - return this.isITAC || useMainStore().isNoComp; - }, - isMobileFeeHidden() { - return this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true'; - }, - isMobileOnly() { - return this.isServiceableMobile && !this.isServiceableInshop; } }, - watch: { - answersToDisplay: { - handler(newValue) { - // If there is only one option to display and that option is 'Mobile' then select it - if ( - newValue.length === 1 - && newValue.findIndex((answer) => (answer.Name === AppointmentTypeStrings.MOBILE)) !== -1 - ) { - this.selectedValues = AppointmentTypeStrings.MOBILE; - } - }, - immediate: true - }, - isMobileOnly: { - handler(newValue) { - if (newValue) { - this.selectedValues = AppointmentTypeStrings.MOBILE; - } - } - } - } }; diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index e38bc1cd..9cc5f595 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -13,18 +13,18 @@ - + -
+
+ {{ appointmentQuestionText }} +
- +
+ +
+ @@ -118,7 +128,6 @@ import { AppointmentTypeStrings } from '@/constants/schedule-constants.js'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import settleAllPromises from '@/helpers/layout-helper'; -import { required } from '@/helpers/validation-rules'; import errorMessages from '@/constants/error-messages'; import { useMainStore } from '@/store'; import { @@ -237,6 +246,7 @@ export default { mobileZipCode: '', mobileZipError: '', showMobileOption: false, + militaryBaseWarningExpanded: false, RECAL_MODAL_REF_NAME, SITE_FOOTER_REF_NAME, errorMessages @@ -277,9 +287,6 @@ export default { || this.selectedAppointmentType === 'Dropoff' ); }, - isAppointmentTypeDisplayed() { - return this.zipCode && !this.displayNoShopsAlert && this.showMobileOption; - }, isMobile() { return this.selectedAppointmentType === AppointmentTypeStrings.MOBILE }, @@ -328,6 +335,15 @@ export default { mobileZipPlaceholder() { return this.getCmsContent('MobileZipPlaceHolderWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT); }, + militaryBaseWarningLinkText() { + return this.getCmsContent('AlertMilitaryBaseZipWidget', widgetFields.ALERT_WIDGET.HEADLINE_TEXT); + }, + militaryBaseWarningText() { + return this.getCmsContent('AlertMilitaryBaseZipWidget', widgetFields.ALERT_WIDGET.BODY_TEXT); + }, + appointmentQuestionText() { + return this.getCmsContent('AppointmentTypeQuestionWidget', widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT); + } }, methods: { arePagePrerequisitesValid() { @@ -424,6 +440,9 @@ export default { if (serviceabilityDetails) { this.setServiceabilityDetails(serviceabilityDetails); this.showMobileOption = this.isServiceableMobile; + if (!this.showMobileOption) { + this.selectedAppointmentType = AppointmentTypeStrings.IN_SHOP; + } } if (mobileFeePart) { @@ -564,10 +583,30 @@ $page-side-padding: 1.5rem; .form-test-error { font-weight: $font-weight-bold; } + .appointment-type-question-text { + color: $black; + font-weight: 600; + margin-bottom: 1rem; + font-size: 1rem; + line-height: 1.625rem; + } .mobile-service-zip-question { :deep(.form-test-error span) { font-weight: $font-weight-bold; } } + .expandable-link-container { + margin-bottom: 1rem; + } + .expandable-link { + font-style: italic; + font-weight: $font-weight-bold; + text-decoration: none; + color: $heritage-blue-primary; + line-height: 1.375rem; + &:hover { + text-decoration: underline; + } + } } diff --git a/src/layouts/service-location/shop-address/shop-address.vue b/src/layouts/service-location/shop-address/shop-address.vue index 88fb545d..cf7239f6 100644 --- a/src/layouts/service-location/shop-address/shop-address.vue +++ b/src/layouts/service-location/shop-address/shop-address.vue @@ -3,7 +3,6 @@ name="fade" mode="out-in">
{{ questionText }}
@@ -122,7 +121,6 @@ export default { serviceZipcode: String, cmsWidgetName: String, validationRules: String, - isDisplayed: Boolean, modalWidgetName: String, selectedAppointmentType: String, }, @@ -229,11 +227,6 @@ export default { }, async searchRadiusInMiles() { await this.updateShops(); - }, - nearbyShops(newShops) { - if (!newShops.find(shop => shop.providerNumber === this.internalProviderNumber)) { - this.internalProviderNumber = ''; - } } }, methods: { @@ -250,6 +243,10 @@ export default { this.errorMessage = errorMessages.ZIP_CODE_NOT_SERVICED_FOR_VEHICLE; } else { + if (!result.find(shop => shop.providerNumber === this.internalProviderNumber)) { + this.internalProviderNumber = ''; + await this.$nextTick(); + } this.nearbyShops = result; this.searchRadiusInMiles = this.searchRadiusArray[currentSearchIndex].Name; } diff --git a/src/styles/ux-variables.scss b/src/styles/ux-variables.scss index b571d788..e8ef6a64 100644 --- a/src/styles/ux-variables.scss +++ b/src/styles/ux-variables.scss @@ -210,6 +210,9 @@ $alert-bg-scale: -90%; $alert-border-scale: -100%; $alert-color-scale: 40%; +$alert-yellow-bg: #fef6e8; +$alert-yellow-color: #e86421; + //Modal animation // This affects all [Bootstrap] modals $modal-fade-transform: translate(0, 100%); diff --git a/src/ux-components/alert/alert.vue b/src/ux-components/alert/alert.vue index ef633fdc..faaa01b5 100644 --- a/src/ux-components/alert/alert.vue +++ b/src/ux-components/alert/alert.vue @@ -1,64 +1,84 @@ @@ -74,6 +94,7 @@ import { import applicationConfig from '@/constants/application-config'; import textBlock from '@/digital-components/text-block/text-block.vue'; import textLink from '@/ux-components/text-link/text-link.vue'; +import { Collapse } from 'bootstrap'; export default { // eslint-disable-next-line vue/multi-word-component-names @@ -84,13 +105,14 @@ export default { }, props: { isDismissible: Boolean, + isCollapsible: Boolean, /* - alertClass class names: - alert-success (green) - alert-danger (red) - alert-warning (yellow) - alert-info (blue) - */ + alertClass class names: + alert-success (green) + alert-danger (red) + alert-warning (yellow) + alert-info (blue) + */ alertClass: String, cmsWidgetName: { type: String, @@ -106,7 +128,14 @@ export default { shouldScrollToOnMount: { type: Boolean, default: true - } + }, + startCollapsed: Boolean + }, + data() { + return { + collapsed: this.startCollapsed || false, + collapseElement: null, + }; }, computed: { pageQueryString() { @@ -124,10 +153,17 @@ export default { }, splitAlertCopyForParagraphTag() { return splitCMSCopyOnParagraphTag(this.alertCopy); - } + }, + collapseId() { + return this.isCollapsible + ? `${this.cmsWidgetName}-collapse` + : null; + }, }, mounted() { this.ensureAlertIsInViewPort(); + this.collapseElement = Collapse.getOrCreateInstance(document.getElementById(this.collapseId)); + }, methods: { doesCopyContainRouterLink, @@ -152,37 +188,81 @@ export default { <= (window.innerHeight - footerHeight || document.documentElement.clientHeight - footerHeight) ); - } + }, + toggleCollapse() { + this.collapsed = !this.collapsed; + if (this.collapsed) { + this.collapseElement.hide(); + } else { + this.collapseElement.show(); + } + }, } }; From d6762e85a85521c4c4f222ac91075558dae09b54 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Fri, 16 Jan 2026 12:20:52 -0500 Subject: [PATCH 12/49] More alert/error/etc updates --- src/constants/error-messages.js | 2 +- .../appointment-type-question.vue | 13 ++- .../service-location/service-location.vue | 110 +++++++++++------- .../shop-address/shop-address.vue | 30 ++++- src/styles/ux-variables.scss | 2 + src/ux-components/alert/alert.vue | 19 +-- 6 files changed, 119 insertions(+), 57 deletions(-) diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index ace5e564..98d19bf2 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -26,7 +26,7 @@ const errorMessages = Object.freeze({ SERVICE_ZIP_REQUIRED: 'ZIP code is required', SERVICE_ZIP_FORMAT: 'Invalid ZIP, please enter a new ZIP (5 characters)', MOBILE_SERVICE_ZIP_FORMAT: 'Invalid ZIP code', - NO_SERVICE_IN_ZIP: (zip) => `We're sorry, but we don't offer service in ${zip} at this time.`, + NO_SERVICE_IN_AREA: (area) => `We're sorry, but we don't offer service in ${area} at this time.`, PROVIDER_REQUIRED: 'Please select a provider.', INVALID_ZIP: 'The ZIP you entered was invalid. Please enter a valid ZIP.', ZIP_CODE_NOT_SERVICED_FOR_VEHICLE: 'We do not currently offer glass service for your vehicle in this ZIP code. Please try another ZIP code.', 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 index d192a27f..f14c51c4 100644 --- a/src/layouts/service-location/appointment-type-question/appointment-type-question.vue +++ b/src/layouts/service-location/appointment-type-question/appointment-type-question.vue @@ -9,7 +9,7 @@ ref="buttonQuestion" v-model="selectedValues" customButtonQuestionId="appointmentTypeQuestion" - :answers="answersFromCms" + :answers="answersToDisplay" :groupName="groupName" :suppressError="suppressError" :validationRules="validationRules" @@ -45,8 +45,15 @@ export default { return this.getCmsContent(this.cmsWidgetName, 'QuestionText'); }, answersFromCms() { - const retCms = this.getCmsContent(this.cmsWidgetName, 'Answers'); - return retCms; + return this.getCmsContent(this.cmsWidgetName, 'Answers'); + }, + answersToDisplay() { + return this.answersFromCms + ? this.answersFromCms.filter((answer) => ( + (answer.Name === AppointmentTypeStrings.IN_SHOP) + || (answer.Name === AppointmentTypeStrings.MOBILE) + )) + : []; }, selectedValues: { get() { diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 9cc5f595..ab684447 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -13,18 +13,6 @@ - - -
- {{ appointmentQuestionText }} + {{ scheduleRecalText }} + {{ appointmentQuestionText }}
+ + +
@@ -105,6 +107,7 @@ cmsWidgetName="MobileFeeDisclaimerWidget" typeStyle="disclaimer" />
+ 0 && !foundMatch) { this.selectedProvider = providers.shopProviders[0]; } + else { + this.selectedProvider = null; + } } if (glassFees) { @@ -485,13 +502,6 @@ export default { setMobileProviderNumber(providerNumber) { this.mobileProviderNumber = providerNumber; }, - resetMobileLocation() { - this.streetAddress = ''; - this.streetAddress2 = ''; - this.city = ''; - - this.isVehicleProtected = null; - }, setServiceabilityDetails(serviceabilityDetails) { this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop; @@ -501,6 +511,9 @@ export default { serviceabilityDetails.isGlassServiceableMobile; this.isRecalibrationServiceableMobile = serviceabilityDetails.isRecalibrationServiceableMobile; + if (!this.isServiceableMobile) { + this.selectedAppointmentType = AppointmentTypeStrings.IN_SHOP; + } }, async updateMobileZip() { this.mobileZipError = ''; @@ -510,8 +523,10 @@ export default { if (!zipCodeData.isValid) { this.mobileZipError = errorMessages.INVALID_ZIP; } else if (!zipCodeData.isServiceable) { - this.mobileZipError = errorMessages.NO_SERVICE_IN_ZIP(this.mobileZipCode); + this.mobileZipError = errorMessages.NO_SERVICE_IN_AREA(toTitleCase(zipCodeData.city)); } else { + console.log('zipCodeData:', zipCodeData); + this.city = zipCodeData.city; this.zipCode = this.mobileZipCode; this.setCtuForMobile(zipCodeData.zipCodeCtu); this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase); @@ -532,6 +547,9 @@ export default { if(providers.shopProviders.length > 0) { this.selectedProvider = providers.shopProviders[0]; } + else { + this.selectedProvider = null; + } } }); } @@ -539,6 +557,8 @@ export default { async handleInShopZipUpdated(newZip) { this.zipCode = newZip; const zipCodeData = await getZipCodeData(this.zipCode); + console.log('zipCodeData:', zipCodeData); + this.city = zipCodeData.city; this.setCtuForMobile(zipCodeData.zipCodeCtu); this.setContainsMilitaryBase(zipCodeData.containsMilitaryBase); @@ -547,7 +567,6 @@ export default { const details = result.data; if (details) { this.setServiceabilityDetails(details); - this.showMobileOption = this.isServiceableMobile; } }); } @@ -589,6 +608,11 @@ $page-side-padding: 1.5rem; margin-bottom: 1rem; font-size: 1rem; line-height: 1.625rem; + flex-direction: column; + .recal-text { + margin-bottom: 1.25rem; + font-weight: $font-weight-bold; + } } .mobile-service-zip-question { :deep(.form-test-error span) { diff --git a/src/layouts/service-location/shop-address/shop-address.vue b/src/layouts/service-location/shop-address/shop-address.vue index cf7239f6..6b4d7402 100644 --- a/src/layouts/service-location/shop-address/shop-address.vue +++ b/src/layouts/service-location/shop-address/shop-address.vue @@ -6,7 +6,9 @@ class="shop-address" aria-live="polite">
{{ questionText }}
-
+
{{ displayedShopName }} {{ modelValue.distanceInMiles?.toFixed(2) }} mi @@ -16,10 +18,22 @@ {{ getProviderCityZipState(modelValue) }}
+
+ {{ `No shops found within 100 miles of ${internalZipcode}` }} +
+
diff --git a/src/layouts/tpa-submit/review-block/review-block.spec.js b/src/layouts/tpa-submit/review-block/review-block.spec.js index 82f3c4e5..f7f6d514 100644 --- a/src/layouts/tpa-submit/review-block/review-block.spec.js +++ b/src/layouts/tpa-submit/review-block/review-block.spec.js @@ -20,12 +20,12 @@ describe('ReviewBlock.vue', () => { }); it('renders the correct number of lines', () => { - const lineElements = wrapper.findAll('.review-block__body--line'); + const lineElements = wrapper.findAll('.review-body p'); expect(lineElements.length).toBe(lines.length); }); it('renders the correct line text', () => { - const lineElements = wrapper.findAll('.review-block__body--line'); + const lineElements = wrapper.findAll('.review-body p'); lines.forEach((line, index) => { expect(lineElements.at(index).text()).toBe(line); }); diff --git a/src/layouts/tpa-submit/tpa-submit.spec.js b/src/layouts/tpa-submit/tpa-submit.spec.js index 7dd6920b..6470f241 100644 --- a/src/layouts/tpa-submit/tpa-submit.spec.js +++ b/src/layouts/tpa-submit/tpa-submit.spec.js @@ -18,7 +18,15 @@ import coverageStatuses from '@/constants/coverage-statuses'; jest.mock('@/helpers/cms-content-helper', () => ({ fetchCmsContentForPage: jest.fn(), doesCopyContainRouterLink: jest.fn(), - getStringWithCustomValues: jest.fn(), + getStringWithCustomValues: jest.fn((str, customValueMap) => { + let newString = str ?? ''; + if (customValueMap != null) { + Object.keys(customValueMap).forEach((key) => { + newString = newString.replaceAll(`{custom:${key}}`, customValueMap[key]); + }); + } + return newString; + }), processIfStatements: jest.fn() })); @@ -129,11 +137,7 @@ describe('tpa-submit', () => { // Assert expect(subHeader.exists()).toBeTruthy(); - expect(subHeader.props().justifyText).toBe('center'); - expect(subHeader.props().marginTopSizeOverride).toBe(4); - expect(subHeader.classes()).toContain('text-color--black'); - expect(subHeader.classes()).toContain('fs-5'); - expect(subHeader.classes()).toContain('tpa-submit__title--line-height'); + expect(subHeader.classes()).toContain('tpa-submit-title'); }); test('sub header body one', () => { // Arrange @@ -144,34 +148,6 @@ describe('tpa-submit', () => { // Assert expect(subHeaderBodyOne.exists()).toBeTruthy(); - expect(subHeaderBodyOne.classes()).toContain('small'); - expect(subHeaderBodyOne.classes()).toContain('text-color--darker-gray'); - }); - test('sub header body two', () => { - // Arrange - const wrapper = shallowMount(tpaSubmit, getMountOptions()); - - // Act - const subHeaderBodyTwo = wrapper.findComponent({ ref: 'tpaSubmitSubHeaderBodyTwo' }); - - // Assert - expect(subHeaderBodyTwo.exists()).toBeTruthy(); - expect(subHeaderBodyTwo.classes()).toContain('mb-4'); - expect(subHeaderBodyTwo.classes()).toContain('small'); - expect(subHeaderBodyTwo.classes()).toContain('text-color--darker-gray'); - }); - test('main button one', () => { - // Arrange - const wrapper = shallowMount(tpaSubmit, getMountOptions()); - - // Act - const mainButton = wrapper.findComponent({ ref: 'buttonMainOne' }); - - // Assert - expect(mainButton.exists()).toBeTruthy(); - expect(mainButton.props().variant).toBe('success'); - expect(mainButton.classes()).toContain('w-100'); - expect(mainButton.classes()).toContain('mb-5'); }); test('service summary section', () => { // Arrange @@ -183,21 +159,6 @@ describe('tpa-submit', () => { // Assert expect(serviceSummarySection.exists()).toBeTruthy(); }); - test('service summary title', () => { - // Arrange - const wrapper = shallowMount(tpaSubmit, getMountOptions()); - - // Act - const serviceSummaryTitle = wrapper.findComponent({ ref: 'tpaSubmitServiceSummaryTitle' }); - - // Assert - expect(serviceSummaryTitle.exists()).toBeTruthy(); - expect(serviceSummaryTitle.props().marginTopSizeOverride).toBe(4); - expect(serviceSummaryTitle.classes()).toContain('fw-bold'); - expect(serviceSummaryTitle.classes()).toContain('fs-1'); - expect(serviceSummaryTitle.classes()).toContain('lh-lg'); - expect(serviceSummaryTitle.classes()).toContain('text-color--black'); - }); describe('review blocks', () => { const title1 = 'Section 1'; const title2 = 'Another Section'; @@ -253,24 +214,8 @@ describe('tpa-submit', () => { // Assert expect(submitOrderDetailsTitle.exists()).toBeTruthy(); - expect(submitOrderDetailsTitle.props().marginTopSizeOverride).toBe(4); expect(submitOrderDetailsTitle.classes()).toContain('fw-bold'); - expect(submitOrderDetailsTitle.classes()).toContain('text-color--black'); - }); - test('submit order details body', () => { - // Arrange - const wrapper = shallowMount(tpaSubmit, getMountOptions()); - - // Act - const submitOrderDetailsTitle = wrapper.findComponent({ ref: 'tpaSubmitOrderDetailsBody' }); - - // Assert - expect(submitOrderDetailsTitle.exists()).toBeTruthy(); - expect(submitOrderDetailsTitle.props().marginTopSizeOverride).toBe(4); - expect(submitOrderDetailsTitle.classes()).toContain('mb-4'); - expect(submitOrderDetailsTitle.classes()).toContain('px-4'); - expect(submitOrderDetailsTitle.classes()).toContain('small'); - expect(submitOrderDetailsTitle.classes()).toContain('text-color--darker-gray'); + expect(submitOrderDetailsTitle.classes()).toContain('order-details-title'); }); test('deductible box', () => { // Arrange @@ -306,7 +251,7 @@ describe('tpa-submit', () => { }); }); describe('before route enter', () => { - test('produces 4 sections', async () => { + test('produces 2 sections', async () => { // Arrange const { wrapper } = getMountedComponent(); expect(wrapper.vm.sections.length).toBe(0); @@ -320,65 +265,13 @@ describe('tpa-submit', () => { ); // Assert - expect(wrapper.vm.sections.length).toBe(4); - }); - test.each([ - ['2004', 'Honda', 'Civic', '2004 Honda Civic'], - [null, 'Honda', 'Civic', 'Honda Civic'], - ['2004', '', 'Civic', '2004 Civic'], - ['2004', 'Honda', null, '2004 Honda'], - ['2004', null, undefined, '2004'], - [null, null, null, ''] - ])( - 'when store vehicle has year %p, make %p, and model %p, has line %p', - async (year, make, model, line) => { - // Arrange - const initialStore = { - order: { - vehicle: { year, make, model } - } - }; - const { wrapper } = getMountedComponent(initialStore); - const vehicleSectionIndex = 0; - const expectedLines = [line]; - - // Act - await tpaSubmit.beforeRouteEnter.call( - wrapper.vm, - { query: { issPage: 'tpa-submit' } }, - undefined, - (c) => c(wrapper.vm) - ); - - // Assert - const vehicleSection = wrapper.vm.sections[vehicleSectionIndex]; - expect(vehicleSection.lines).toStrictEqual(expectedLines); - } - ); - 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) - ); - - // Assert - const damageSection = wrapper.vm.sections[damageSectionIndex]; - expect(damageSection.lines).toEqual(expectedLines); + expect(wrapper.vm.sections.length).toBe(2); }); describe('preferred shop section', () => { - test('has three lines', async () => { + test('has two lines', async () => { // Arrange const { wrapper } = getMountedComponent(); - const preferredShopSectionIndex = 2; + const preferredShopSectionIndex = 0; // Act await tpaSubmit.beforeRouteEnter.call( @@ -390,15 +283,15 @@ describe('tpa-submit', () => { // Assert const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex]; - expect(preferredShopSection.lines.length).toBe(3); + expect(preferredShopSection.lines.length).toBe(2); }); - test('first line is value returned from toTitleCase method', async () => { + test('title is value returned from toTitleCase method', async () => { // Arrange const initialData = { companyName: 'some value' }; const { wrapper } = getMountedComponent({}, initialData); const expectedName = 'some expected name'; toTitleCase.mockImplementationOnce(() => expectedName); - const preferredShopSectionIndex = 2; + const preferredShopSectionIndex = 0; // Act await tpaSubmit.beforeRouteEnter.call( @@ -410,9 +303,9 @@ describe('tpa-submit', () => { // Assert const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex]; - expect(preferredShopSection.lines[0]).toBe(expectedName); + expect(preferredShopSection.title).toBe(expectedName); }); - test('second line is expected and formatAddress called', async () => { + test('first line is expected and formatAddress called', async () => { // Arrange const address = { streetAddress: '123 South Ln', @@ -430,7 +323,7 @@ describe('tpa-submit', () => { const { wrapper } = getMountedComponent(initialStore); const line = 'some returned line'; formatAddress.mockImplementationOnce(() => line); - const preferredShopSectionIndex = 2; + const preferredShopSectionIndex = 0; // Act await tpaSubmit.beforeRouteEnter.call( @@ -442,7 +335,7 @@ describe('tpa-submit', () => { // Assert const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex]; - expect(preferredShopSection.lines[1]).toBe(line); + expect(preferredShopSection.lines[0]).toBe(line); expect(formatAddress).toHaveBeenCalledTimes(1); expect(formatAddress).toHaveBeenCalledWith( address.streetAddress, @@ -452,7 +345,7 @@ describe('tpa-submit', () => { address.zipCode ); }); - test('third line is expected and toDisplayPhoneNumber called', async () => { + test('second line is expected and toDisplayPhoneNumber called', async () => { // Arrange const phoneNumber = '9998887777'; const initialStore = { @@ -465,7 +358,7 @@ describe('tpa-submit', () => { const { wrapper } = getMountedComponent(initialStore); const expectedLine = 'returned from to display phone num'; toDisplayPhoneNumber.mockImplementationOnce(() => expectedLine); - const preferredShopSectionIndex = 2; + const preferredShopSectionIndex = 0; // Act await tpaSubmit.beforeRouteEnter.call( @@ -477,7 +370,7 @@ describe('tpa-submit', () => { // Assert const preferredShopSection = wrapper.vm.sections[preferredShopSectionIndex]; - expect(preferredShopSection.lines[2]).toBe(expectedLine); + expect(preferredShopSection.lines[1]).toBe(expectedLine); expect(toDisplayPhoneNumber).toHaveBeenCalledWith(phoneNumber); }); }); @@ -487,8 +380,14 @@ describe('tpa-submit', () => { const lastName = 'Eddison'; const emailAddress = 'myname@gmail.com'; const servicePhone = '0001112222'; + const providerCompanyName = 'Some Provider LLC'; const initialStore = { order: { + serviceLocation: { + provider: { + companyName: providerCompanyName + } + }, contactInfo: { firstName, lastName, @@ -498,11 +397,11 @@ describe('tpa-submit', () => { } }; const { wrapper } = getMountedComponent(initialStore); - const expectedLine1 = 'Jones Eddison'; - const expectedLine2 = emailAddress; - const expectedLine3 = 'some value returned'; - toDisplayPhoneNumber.mockImplementation((number) => (number === servicePhone ? expectedLine3 : '')); - const contactInfoSectionIndex = 3; + const expectedEmail = emailAddress; + const expectedPhone = 'some value returned'; + toDisplayPhoneNumber.mockImplementation((number) => (number === servicePhone ? expectedPhone : '')); + const contactInfoSectionIndex = 1; + wrapper.vm.getCmsContent.mockImplementation(() => '{custom:contactPhone} or {custom:contactEmail}'); // Act await tpaSubmit.beforeRouteEnter.call( @@ -511,12 +410,12 @@ describe('tpa-submit', () => { undefined, (c) => c(wrapper.vm) ); + wrapper.vm.setSections(); // Assert const contactInfoSection = wrapper.vm.sections[contactInfoSectionIndex]; - expect(contactInfoSection.lines[0]).toBe(expectedLine1); - expect(contactInfoSection.lines[1]).toBe(expectedLine2); - expect(contactInfoSection.lines[2]).toBe(expectedLine3); + expect(contactInfoSection.lines[0]).toContain(expectedEmail); + expect(contactInfoSection.lines[0]).toContain(expectedPhone); expect(toDisplayPhoneNumber).toHaveBeenCalledWith(servicePhone); }); }); @@ -524,7 +423,6 @@ describe('tpa-submit', () => { test.each([ ['subHeaderTitle', 'SiteSubHeaderWidget', widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT, 'site sub header'], ['subHeaderBodyOne', 'SiteSubHeaderWidget', widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT, 'sub header body one'], - ['serviceSummaryText', 'ServiceSummaryContent', widgetFields.TEXT_BLOCK_WIDGET.TEXT, 'service summary text'], ['orderDetailsTitle', 'OrderDetailsContent', widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT, 'order details title'], ['forwardButtonText', 'SiteFooterWidget', widgetFields.FOOTER_WIDGET.FORWARD_BUTTON_TEXT, 'forward button text'] ])('computed %p returns expected value', (computedName, widgetLabel, fieldLabel, expected) => { diff --git a/src/layouts/tpa-submit/tpa-submit.vue b/src/layouts/tpa-submit/tpa-submit.vue index aa334adf..ff3824bc 100644 --- a/src/layouts/tpa-submit/tpa-submit.vue +++ b/src/layouts/tpa-submit/tpa-submit.vue @@ -180,12 +180,6 @@ export default { ); return getStringWithCustomValues(cmsContent, this.customValueMap); }, - serviceSummaryText() { - return this.getCmsContent( - this.widget.serviceSummary, - widgetFields.TEXT_BLOCK_WIDGET.TEXT - ); - }, orderDetailsTitle() { return this.getCmsContent( this.widget.orderDetails, From 2750d98f36f1e7a2ff3eb8ada135aafcba21f45b Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Wed, 21 Jan 2026 16:11:37 -0500 Subject: [PATCH 40/49] Remove debug console.logs --- .../contact-details-drawer.vue | 14 -------------- src/store/index.js | 2 -- 2 files changed, 16 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 931b950e..9c94782a 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 @@ -79,13 +79,6 @@ export default { emailAddress, servicePhone, extension } = useMainStore().contactInfo; - console.log('Initial contact info loaded:', { - firstName, - lastName, - emailAddress, - servicePhone, - extension - }); return { isModalOpened: false, firstName, @@ -157,13 +150,6 @@ export default { emailAddress, servicePhone, extension } = this.mainStore.contactInfo; - console.log('Resetting form values to:', { - firstName, - lastName, - emailAddress, - servicePhone, - extension - }); this.firstName = firstName; this.lastName = lastName; this.emailAddress = emailAddress; diff --git a/src/store/index.js b/src/store/index.js index 3959bd62..dafc9402 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2574,8 +2574,6 @@ export const useMainStore = defineStore({ updatePhoneNumbers(phoneNumbers) { const contact = this.order.contactInfo; - console.log('Updating phone numbers with:', phoneNumbers); - console.log('Current contact info before update:', contact); contact.homePhone = phoneNumbers.home !== undefined ? phoneNumbers.home : contact.homePhone; contact.alternativePhone = phoneNumbers.alternative !== undefined ? phoneNumbers.alternative : contact.alternativePhone; contact.servicePhone = phoneNumbers.service !== undefined ? phoneNumbers.service : contact.servicePhone; From d4530ca4cf229f48b5dd85b08d9dbb0a8582de67 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Wed, 21 Jan 2026 17:17:20 -0500 Subject: [PATCH 41/49] Add extension to save/load session --- src/layouts/tpa-submit/tpa-submit.spec.js | 47 +++++++++++++++++++++++ src/layouts/tpa-submit/tpa-submit.vue | 6 ++- src/store/index.js | 5 ++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/layouts/tpa-submit/tpa-submit.spec.js b/src/layouts/tpa-submit/tpa-submit.spec.js index 6470f241..ab42d2f5 100644 --- a/src/layouts/tpa-submit/tpa-submit.spec.js +++ b/src/layouts/tpa-submit/tpa-submit.spec.js @@ -418,6 +418,53 @@ describe('tpa-submit', () => { expect(contactInfoSection.lines[0]).toContain(expectedPhone); expect(toDisplayPhoneNumber).toHaveBeenCalledWith(servicePhone); }); + test('contact info section has expected content with extension', async () => { + // Arrange + const firstName = 'Jones'; + const lastName = 'Eddison'; + const emailAddress = 'myname@gmail.com'; + const servicePhone = '0001112222'; + const extension = '12345'; + const providerCompanyName = 'Some Provider LLC'; + const initialStore = { + order: { + serviceLocation: { + provider: { + companyName: providerCompanyName + } + }, + contactInfo: { + firstName, + lastName, + emailAddress, + servicePhone, + extension + } + } + }; + const { wrapper } = getMountedComponent(initialStore); + const expectedEmail = emailAddress; + const expectedPhone = 'some value returned'; + toDisplayPhoneNumber.mockImplementation((number) => (number === servicePhone ? expectedPhone : '')); + const contactInfoSectionIndex = 1; + wrapper.vm.getCmsContent.mockImplementation(() => '{custom:contactPhone} or {custom:contactEmail}'); + + // Act + await tpaSubmit.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: 'tpa-submit' } }, + undefined, + (c) => c(wrapper.vm) + ); + wrapper.vm.setSections(); + + // Assert + const contactInfoSection = wrapper.vm.sections[contactInfoSectionIndex]; + expect(contactInfoSection.lines[0]).toContain(expectedEmail); + expect(contactInfoSection.lines[0]).toContain(expectedPhone); + expect(contactInfoSection.lines[0]).toContain(`Ext. ${extension}`); + expect(toDisplayPhoneNumber).toHaveBeenCalledWith(servicePhone); + }); }); describe('computed', () => { test.each([ diff --git a/src/layouts/tpa-submit/tpa-submit.vue b/src/layouts/tpa-submit/tpa-submit.vue index ff3824bc..eba5129a 100644 --- a/src/layouts/tpa-submit/tpa-submit.vue +++ b/src/layouts/tpa-submit/tpa-submit.vue @@ -275,9 +275,13 @@ export default { return this.mainStore.hasRecalibrationPart; }, customValueMap() { + let contactPhone = toDisplayPhoneNumber(this.mainStore.contactInfo.servicePhone); + if (this.mainStore.contactInfo.extension) { + contactPhone += ` Ext. ${this.mainStore.contactInfo.extension}`; + } return { glassShop: this.getPreferredShopTitle, - contactPhone: toDisplayPhoneNumber(this.mainStore.contactInfo.servicePhone), + contactPhone: contactPhone, contactEmail: this.mainStore.contactInfo.emailAddress } } diff --git a/src/store/index.js b/src/store/index.js index dafc9402..9f710b03 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1457,7 +1457,7 @@ export const useMainStore = defineStore({ emailAddress: contactInfo.emailAddress || customer.emailAddress, firstName: contactInfo.firstName || customer.firstName, lastName: contactInfo.lastName || customer.lastName, - homePhone: contactInfo.homePhone, + homePhone: contactInfo.extension ? contactInfo.servicePhone + contactInfo.extension : contactInfo.homePhone, servicePhone: contactInfo.servicePhone, alternativePhone: contactInfo.alternativePhone, isSmsOptIn: contactInfo.requestTextUpdates ?? false @@ -1592,6 +1592,7 @@ export const useMainStore = defineStore({ order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; order.contactInfo.homePhone = data?.customer?.homePhone; + order.contactInfo.extension = data?.customer?.homePhone?.length > 10 ? data.customer.homePhone.slice(10) : ''; order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; @@ -1660,6 +1661,7 @@ export const useMainStore = defineStore({ order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; order.contactInfo.homePhone = data?.customer?.homePhone; + order.contactInfo.extension = data?.customer?.homePhone?.length > 10 ? data.customer.homePhone.slice(10) : ''; order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; @@ -2097,6 +2099,7 @@ export const useMainStore = defineStore({ this.order.contactInfo.homePhone = null; this.order.contactInfo.alternativePhone = null; this.order.contactInfo.servicePhone = null; + this.order.contactInfo.extension = null; this.order.contactInfo.requestTextUpdates = false; this.order.contactInfo.notesForTechnician = ''; }, From 36771caca30d5acd14a3e0968b8662c8476b6603 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Wed, 21 Jan 2026 17:24:34 -0500 Subject: [PATCH 42/49] Properly split extension from homePhone on load --- src/store/index.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 9f710b03..15b51802 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1591,8 +1591,14 @@ export const useMainStore = defineStore({ order.contactInfo.firstName = data?.customer?.firstName; order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; - order.contactInfo.homePhone = data?.customer?.homePhone; - order.contactInfo.extension = data?.customer?.homePhone?.length > 10 ? data.customer.homePhone.slice(10) : ''; + if (data?.customer?.homePhone?.length > 10) { + order.contactInfo.extension = data.customer.homePhone.slice(10); + order.contactInfo.homePhone = data.customer.homePhone.slice(0, 10); + } + else { + order.contactInfo.homePhone = data?.customer?.homePhone; + order.contactInfo.extension = ''; + } order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; @@ -1660,8 +1666,14 @@ export const useMainStore = defineStore({ order.contactInfo.firstName = data?.customer?.firstName; order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; - order.contactInfo.homePhone = data?.customer?.homePhone; - order.contactInfo.extension = data?.customer?.homePhone?.length > 10 ? data.customer.homePhone.slice(10) : ''; + if (data?.customer?.homePhone?.length > 10) { + order.contactInfo.extension = data.customer.homePhone.slice(10); + order.contactInfo.homePhone = data.customer.homePhone.slice(0, 10); + } + else { + order.contactInfo.homePhone = data?.customer?.homePhone; + order.contactInfo.extension = ''; + } order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; From ebb16e1c52e33faab556a1b7028383faeaa8ba55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 04:35:19 +0000 Subject: [PATCH 43/49] Bump lodash from 4.17.21 to 4.17.23 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.17.23 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index e981a8a8..ef58e600 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15557,10 +15557,11 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", From 7965fe9137f89d279e7dfdfe7683480e97acbcf8 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 22 Jan 2026 09:13:46 -0500 Subject: [PATCH 44/49] Fix issues raised by bugbot --- src/layouts/tpa-submit/tpa-submit.vue | 2 +- src/store/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layouts/tpa-submit/tpa-submit.vue b/src/layouts/tpa-submit/tpa-submit.vue index eba5129a..85a85d52 100644 --- a/src/layouts/tpa-submit/tpa-submit.vue +++ b/src/layouts/tpa-submit/tpa-submit.vue @@ -282,7 +282,7 @@ export default { return { glassShop: this.getPreferredShopTitle, contactPhone: contactPhone, - contactEmail: this.mainStore.contactInfo.emailAddress + contactEmail: this.mainStore.contactInfo.emailAddress ?? '' } } }, diff --git a/src/store/index.js b/src/store/index.js index 15b51802..9923c99a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1457,7 +1457,7 @@ export const useMainStore = defineStore({ emailAddress: contactInfo.emailAddress || customer.emailAddress, firstName: contactInfo.firstName || customer.firstName, lastName: contactInfo.lastName || customer.lastName, - homePhone: contactInfo.extension ? contactInfo.servicePhone + contactInfo.extension : contactInfo.homePhone, + homePhone: contactInfo.extension && contactInfo.homePhone ? contactInfo.homePhone + contactInfo.extension : contactInfo.homePhone, servicePhone: contactInfo.servicePhone, alternativePhone: contactInfo.alternativePhone, isSmsOptIn: contactInfo.requestTextUpdates ?? false From 09f6d39f18e8da73d7419ef65d2220b74463c8d4 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 22 Jan 2026 09:43:47 -0500 Subject: [PATCH 45/49] Simplify home phone/extension slicing --- src/store/index.js | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/store/index.js b/src/store/index.js index 9923c99a..2bc88be8 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1591,14 +1591,8 @@ export const useMainStore = defineStore({ order.contactInfo.firstName = data?.customer?.firstName; order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; - if (data?.customer?.homePhone?.length > 10) { - order.contactInfo.extension = data.customer.homePhone.slice(10); - order.contactInfo.homePhone = data.customer.homePhone.slice(0, 10); - } - else { - order.contactInfo.homePhone = data?.customer?.homePhone; - order.contactInfo.extension = ''; - } + order.contactInfo.extension = data.customer.homePhone?.slice(10); + order.contactInfo.homePhone = data.customer.homePhone?.slice(0, 10); order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; @@ -1666,14 +1660,8 @@ export const useMainStore = defineStore({ order.contactInfo.firstName = data?.customer?.firstName; order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; - if (data?.customer?.homePhone?.length > 10) { - order.contactInfo.extension = data.customer.homePhone.slice(10); - order.contactInfo.homePhone = data.customer.homePhone.slice(0, 10); - } - else { - order.contactInfo.homePhone = data?.customer?.homePhone; - order.contactInfo.extension = ''; - } + order.contactInfo.extension = data.customer.homePhone?.slice(10); + order.contactInfo.homePhone = data.customer.homePhone?.slice(0, 10); order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; From c0672a0abc9cd1d49fa23fd64d4290a62fef898f Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 22 Jan 2026 10:04:21 -0500 Subject: [PATCH 46/49] bugfix --- 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 2bc88be8..ba0bae56 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1591,8 +1591,8 @@ export const useMainStore = defineStore({ order.contactInfo.firstName = data?.customer?.firstName; order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; - order.contactInfo.extension = data.customer.homePhone?.slice(10); - order.contactInfo.homePhone = data.customer.homePhone?.slice(0, 10); + order.contactInfo.extension = data?.customer?.homePhone?.slice(10); + order.contactInfo.homePhone = data?.customer?.homePhone?.slice(0, 10); order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; From 58f55554f5e25c2b77fd6f6f7a00864d4bab4217 Mon Sep 17 00:00:00 2001 From: Alex Humphries Date: Thu, 22 Jan 2026 10:22:09 -0500 Subject: [PATCH 47/49] bugfix --- 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 ba0bae56..d27f0f2d 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1660,8 +1660,8 @@ export const useMainStore = defineStore({ order.contactInfo.firstName = data?.customer?.firstName; order.contactInfo.lastName = data?.customer?.lastName; order.contactInfo.emailAddress = data?.customer?.emailAddress; - order.contactInfo.extension = data.customer.homePhone?.slice(10); - order.contactInfo.homePhone = data.customer.homePhone?.slice(0, 10); + order.contactInfo.extension = data?.customer?.homePhone?.slice(10); + order.contactInfo.homePhone = data?.customer?.homePhone?.slice(0, 10); order.contactInfo.servicePhone = data?.customer?.servicePhone; order.contactInfo.alternativePhone = data?.customer?.alternativePhone; order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn; From 43c9e987a48af541522a392d82674fa7cb559479 Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Thu, 22 Jan 2026 12:38:05 -0500 Subject: [PATCH 48/49] Moving the clear duplicate orders call around to coverage more use cases. --- src/layouts/duplicate-check/duplicate-check.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/duplicate-check/duplicate-check.vue b/src/layouts/duplicate-check/duplicate-check.vue index f9d2815e..33ad86ef 100644 --- a/src/layouts/duplicate-check/duplicate-check.vue +++ b/src/layouts/duplicate-check/duplicate-check.vue @@ -137,7 +137,6 @@ export default { async forwardButtonAction() { // If user clicked foward without selecting an option or user click on "start a new claim" button. if (this.selectedAnswer == null || this.selectedAnswer === 'NewClaim') { - this.mainStore.updateDuplicateCheckVisited(true); this.navigateForward(); return; } @@ -156,6 +155,7 @@ export default { } }, navigateForward() { + this.mainStore.updateDuplicateCheckVisited(true); if (!this.mainStore.isPolicyLookupSuccessful) { this.$router.navigate( this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED, From 59abdfc4c3bc87133d8398d496d22570cf86f89f Mon Sep 17 00:00:00 2001 From: Jeremy-Z Date: Thu, 22 Jan 2026 12:38:05 -0500 Subject: [PATCH 49/49] Moving the duplicate page seen flag set call around to coverage more use cases. --- src/layouts/duplicate-check/duplicate-check.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/duplicate-check/duplicate-check.vue b/src/layouts/duplicate-check/duplicate-check.vue index f9d2815e..33ad86ef 100644 --- a/src/layouts/duplicate-check/duplicate-check.vue +++ b/src/layouts/duplicate-check/duplicate-check.vue @@ -137,7 +137,6 @@ export default { async forwardButtonAction() { // If user clicked foward without selecting an option or user click on "start a new claim" button. if (this.selectedAnswer == null || this.selectedAnswer === 'NewClaim') { - this.mainStore.updateDuplicateCheckVisited(true); this.navigateForward(); return; } @@ -156,6 +155,7 @@ export default { } }, navigateForward() { + this.mainStore.updateDuplicateCheckVisited(true); if (!this.mainStore.isPolicyLookupSuccessful) { this.$router.navigate( this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,