Merge branch 'develop' into feature/INSR-8130

This commit is contained in:
Jeremy-Z 2026-02-04 11:38:00 -05:00
commit b3f0dd0163
6 changed files with 6131 additions and 7420 deletions

13438
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -56,7 +56,8 @@
"babel-jest": "^27.0.6", "babel-jest": "^27.0.6",
"concurrently": "^9.1.2", "concurrently": "^9.1.2",
"dotenv-safe": "^9.1.0", "dotenv-safe": "^9.1.0",
"eslint": "^9.26.0", "eslint": "^9.39.2",
"eslint-plugin-vue": "^9.15.1",
"form-data": "^4.0.4", "form-data": "^4.0.4",
"jest": "^27.0.5", "jest": "^27.0.5",
"jest-junit": "^13.0.0", "jest-junit": "^13.0.0",

View file

@ -176,7 +176,7 @@ const getAvailableDates = async (
storeAction.payload.shopAppointmentType, storeAction.payload.shopAppointmentType,
storeAction.payload.providerNumber storeAction.payload.providerNumber
); );
} else { } else if (storeAction.payload?.zipCodeOverride) {
timeSlotsResponse = await useMainStore().getMobileTimeSlots( timeSlotsResponse = await useMainStore().getMobileTimeSlots(
storeAction.payload.startDate, storeAction.payload.startDate,
storeAction.payload.endDate, storeAction.payload.endDate,
@ -461,7 +461,7 @@ export default {
const initialEndDate = new Date(); const initialEndDate = new Date();
initialEndDate.setDate(initialEndDate.getDate() + (initialDays - 1)); initialEndDate.setDate(initialEndDate.getDate() + (initialDays - 1));
let initialViewEndDate = convertDateToDateString(initialEndDate); let initialViewEndDate = convertDateToDateString(initialEndDate);
const preSelectedDate = this.mainStore.order.schedule.date; const preSelectedDate = this.selectedDate;
const endDateObject = this.getEndDateForExistingDate( const endDateObject = this.getEndDateForExistingDate(
todayDateObject, todayDateObject,
@ -609,12 +609,18 @@ export default {
} }
}, },
async refreshDatePicker() { async refreshDatePicker() {
this.resetLocalFlags();
await this.getDatePickerInitialData().then((data) => { await this.getDatePickerInitialData().then((data) => {
this.selectableDatesData = data.initialShopTimeSlotsResponse; this.selectableDatesData = data.initialShopTimeSlotsResponse;
this.$refs.datePicker.initializeComponent(data); this.$refs.datePicker.initializeComponent(data);
showIssLoadingModal(false); showIssLoadingModal(false);
}); });
}, },
resetLocalFlags() {
this.selectedDate = null;
this.selectedTimeSlotInfo = null;
this.showDatePickerError = false;
},
timeSlotSelectedFromPicker(timeSlot) { timeSlotSelectedFromPicker(timeSlot) {
this.selectedTimeSlotInfo = timeSlot; this.selectedTimeSlotInfo = timeSlot;
this.showDatePickerError = false; this.showDatePickerError = false;

View file

@ -47,8 +47,21 @@
v-if="displayLowAvailabilityInshop" v-if="displayLowAvailabilityInshop"
ref="alertLowAvailabilityInshop" ref="alertLowAvailabilityInshop"
cmsWidgetName="AlertLowAvailabilityInshopWidget" cmsWidgetName="AlertLowAvailabilityInshopWidget"
:manualHeadlineLineTwo="getLowAvailabilityHeadlineLineTwoText"
:isCollapsible="true" :isCollapsible="true"
alertClass="alert-warning" /> :startCollapsed="true"
alertClass="alert-warning">
<template #headline-line-two>
<button
class="m-0 alert-header-text d-block looka-likea-link"
type="button"
@click="triggerShopAddressModal">
<span class="m-0">
{{ getLowAvailabilityHeadlineLineTwoText }}
</span>
</button>
</template>
</alert>
<shopAddress <shopAddress
ref="shopAddress" ref="shopAddress"
v-model="selectedProvider" v-model="selectedProvider"
@ -201,6 +214,9 @@ export default {
displayServiceableMobileOnly() { displayServiceableMobileOnly() {
return this.isServiceableMobile && this.recalibrationRequired && !this.isServiceableInshop; return this.isServiceableMobile && this.recalibrationRequired && !this.isServiceableInshop;
}, },
getLowAvailabilityHeadlineLineTwoText() {
return 'Try a different location';
},
inShopOnlyCopy() { inShopOnlyCopy() {
let content = this.getCmsContent('AlertInshopOnlyWidget', widgetFields.ALERT_WIDGET.BODY_TEXT); let content = this.getCmsContent('AlertInshopOnlyWidget', widgetFields.ALERT_WIDGET.BODY_TEXT);
content = content.replace('{custom:city}', toTitleCase(this.city)); content = content.replace('{custom:city}', toTitleCase(this.city));
@ -314,7 +330,7 @@ export default {
} }
}, },
selectedProvider(newProvider, oldProvider) { selectedProvider(newProvider, oldProvider) {
if (newProvider?.providerNumber !== oldProvider?.providerNumber) { if (newProvider?.providerNumber !== oldProvider?.providerNumber || this.availabilityRating === null) {
const appointmentIsInshop = this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP; const appointmentIsInshop = this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP;
const returnedProvider = { const returnedProvider = {
provider: newProvider, provider: newProvider,
@ -325,7 +341,9 @@ export default {
this.refreshAvailabilityRating(); this.refreshAvailabilityRating();
} }
this.$emit('provider-changed', returnedProvider); if (newProvider?.providerNumber !== oldProvider?.providerNumber) {
this.$emit('provider-changed', returnedProvider);
}
} }
} }
}, },
@ -492,6 +510,9 @@ export default {
this.selectedAppointmentType = AppointmentTypeStrings.IN_SHOP; this.selectedAppointmentType = AppointmentTypeStrings.IN_SHOP;
} }
}, },
triggerShopAddressModal() {
this.$refs.shopAddress.openModal();
},
async updateMobileZip() { async updateMobileZip() {
this.mobileZipError = ''; this.mobileZipError = '';
const zipCodeData = await getMobileZipCodeData(this.mobileZipCode); const zipCodeData = await getMobileZipCodeData(this.mobileZipCode);
@ -577,5 +598,30 @@ $page-side-padding: 1.5rem;
text-decoration: underline; text-decoration: underline;
} }
} }
div.alert {
margin-top: 0.625rem;
:deep(.alert-header) {
button.btn-collapse {
display: block;
}
}
button.looka-likea-link {
background: none;
border: none;
font-weight: 500;
font-size: 1rem;
padding: 0;
color: $heritage-blue-primary;
text-decoration: none;
cursor: pointer;
&:hover {
color: #125b7e;
text-decoration: underline;
}
}
}
} }
</style> </style>

View file

@ -6,8 +6,8 @@
class="shop-address" class="shop-address"
aria-live="polite"> aria-live="polite">
<div class="address-header"> <div class="address-header">
{{ questionText }} {{ questionText }}
</div> </div>
<div <div
v-if="modelValue" v-if="modelValue"
class="current-address"> class="current-address">
@ -16,8 +16,8 @@
<span class="shop-distance">{{ modelValue.distanceInMiles?.toFixed(2) }} mi</span> <span class="shop-distance">{{ modelValue.distanceInMiles?.toFixed(2) }} mi</span>
</div> </div>
<div class="address-line"> <div class="address-line">
{{ getProviderAddress(modelValue) }} {{ getProviderAddress(modelValue) }}
</div> </div>
<div class="address-line"> <div class="address-line">
{{ getProviderCityZipState(modelValue) }} {{ getProviderCityZipState(modelValue) }}
</div> </div>

View file

@ -23,9 +23,14 @@
0 0 0-.127-.37.489.489 0 0 0-.388-.205z" /> 0 0 0-.127-.37.489.489 0 0 0-.388-.205z" />
</svg> </svg>
</div> </div>
<span class="m-0 alert-header-text"> <template v-if="alertHeadline">
{{ alertHeadline }} <div class="alert-headline-text-container">
</span> <span class="m-0 alert-header-text d-block">
{{ alertHeadline }}
</span>
<slot name="headline-line-two"></slot>
</div>
</template>
<button <button
v-if="isCollapsible" v-if="isCollapsible"
class="btn-collapse" class="btn-collapse"
@ -65,7 +70,7 @@
<div <div
v-show="alertCopy" v-show="alertCopy"
:id="collapseId" :id="collapseId"
class="alert-body"> class="alert-body show">
<template <template
v-for="paragraph in splitAlertCopyForParagraphTag" v-for="paragraph in splitAlertCopyForParagraphTag"
:key="paragraph"> :key="paragraph">
@ -146,12 +151,19 @@ export default {
} }
}, },
manualHeadline: String, manualHeadline: String,
manualHeadlineLineTwo: {
type: String,
default: ''
},
manualCopy: String, manualCopy: String,
shouldScrollToOnMount: { shouldScrollToOnMount: {
type: Boolean, type: Boolean,
default: true default: true
}, },
startCollapsed: Boolean startCollapsed: {
type: Boolean,
default: false
}
}, },
emits: ['textLinkClicked'], emits: ['textLinkClicked'],
data() { data() {
@ -169,11 +181,19 @@ export default {
? this.manualHeadline ? this.manualHeadline
: this.getCmsContent(this.cmsWidgetName, 'HeadlineText'); : this.getCmsContent(this.cmsWidgetName, 'HeadlineText');
}, },
alertHeadlineLineTwo() {
return this.manualHeadlineLineTwo
? this.manualHeadlineLineTwo
: '';
},
alertCopy() { alertCopy() {
return this.manualCopy return this.manualCopy
? this.manualCopy ? this.manualCopy
: this.getCmsContent(this.cmsWidgetName, 'BodyText'); : this.getCmsContent(this.cmsWidgetName, 'BodyText');
}, },
hasManualHeadlineLineTwo() {
return this.manualHeadlineLineTwo !== '';
},
splitAlertCopyForParagraphTag() { splitAlertCopyForParagraphTag() {
return splitCMSCopyOnParagraphTag(this.alertCopy); return splitCMSCopyOnParagraphTag(this.alertCopy);
}, },
@ -186,7 +206,7 @@ export default {
mounted() { mounted() {
this.ensureAlertIsInViewPort(); this.ensureAlertIsInViewPort();
if (this.isCollapsible) { if (this.isCollapsible) {
this.collapseElement = Collapse.getOrCreateInstance(document.getElementById(this.collapseId)); this.collapseElement = Collapse.getOrCreateInstance(document.getElementById(this.collapseId), { toggle: this.startCollapsed });
} }
}, },
methods: { methods: {
@ -230,6 +250,14 @@ export default {
border: 1px solid; border: 1px solid;
padding: 0rem; padding: 0rem;
margin-bottom: 2rem; margin-bottom: 2rem;
.alert-headline-text-container {
flex-grow: 1;
padding: 0rem 0.625rem;
.alert-header-text {
padding: 0;
}
}
.alert-header { .alert-header {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;