diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 4cc75f701..16b259547 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -36,9 +36,13 @@ :id="modalId + '-modalbtn'" ref="modalButtonMain" loaderColor="white" + :isDisabled="footerButtonDisabled" :buttonText="footerButtonText" @click-event="validateAndEmit" - :class="isFooterButtonDisabled && 'form-test-invalid'" /> + :class="[ + isFooterButtonDisabled && 'form-test-invalid', + { 'form-test-invalid': footerButtonDisabled === true }, + ]" /> @@ -59,6 +63,7 @@ export default { footerButtonText: String, suppressPageScroll: Boolean, staticBackdrop: Boolean, + footerButtonDisabled: Boolean, onModalOpenedCallback: { type: Function, }, diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue index 776fe1199..329b99840 100644 --- a/src/layouts/service-location/service-location.vue +++ b/src/layouts/service-location/service-location.vue @@ -115,9 +115,9 @@ :selectedAppointmentType="selectedAppointmentType" :modelValue="{ zipCode: zipCode, - providerNumber: selectedProvider?.providerNumber, + state: state, }" - :preselectedProviderNumber="selectedProvider?.providerNumber" + :preSelectedProviderNumber="selectedProvider?.providerNumber" :shopProviderData="shopProviderData" :isServiceableInshop="isServiceableInshop" @updated-serviceability="setServiceabilityDetails" @@ -844,25 +844,10 @@ export default { let provider = this.shopProviderData?.shopProviders?.find( (p) => p.providerNumber === providerObject?.providerNumber ); - if (!provider && this.shopProviderData?.shopProviders?.length > 0) { - provider = this.shopProviderData.shopProviders[0]; - } this.selectedProvider = provider; - if (provider && provider.address) { - this.zipCode = provider.address.zipCode; - this.state = provider.address.state; - } - if ( - !this.selectedProvider || - !this.shopProviderData?.shopProviders?.some( - (p) => p.providerNumber === this.selectedProvider?.providerNumber - ) - ) { - this.selectedProvider = this.shopProviderData?.shopProviders?.[0]; - } if (providerObject && providerObject.address) { - this.zipCode = providerObject.address.zipCode; - this.state = providerObject.address.state; + this.zipCode = providerObject.searchedZip; + this.state = providerObject.searchedState; } }, setZipcodeCtu(zipcodeCtu) { diff --git a/src/layouts/service-location/shop-question/shop-question-popup.vue b/src/layouts/service-location/shop-question/shop-question-popup.vue index b345d370d..bcf8281b3 100644 --- a/src/layouts/service-location/shop-question/shop-question-popup.vue +++ b/src/layouts/service-location/shop-question/shop-question-popup.vue @@ -1,18 +1,10 @@ @@ -124,6 +90,7 @@ import { required } from "@/helpers/validation-rules"; import { errorMessages } from "@/constants/error-messages"; import baseMixin from "@/mixins/base-mixin.js"; import { nextTick } from "vue"; +import { regex } from "@/helpers/validation-rules"; import { getAvailabilityRating } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper"; @@ -141,13 +108,7 @@ import { } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper"; defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); - -function getShopsByZip(zipCode, shops, numberToGet = 3) { - return shops - .filter((shop) => shop.address && shop.address.zipCode && shop.address.zipCode !== "") - .sort((a, b) => a.distanceInMiles - b.distanceInMiles) - .slice(0, numberToGet); -} +defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)); export default { name: "shop-question-popup", @@ -167,6 +128,9 @@ export default { lastSearchedZip: "", lastSuccessfulZip: "", hasLoadedShopData: false, + displayInvalidZipAlert: false, + areShopsAvialable: true, + displayNoShopsAlert: false, }; }, props: { @@ -193,7 +157,7 @@ export default { default: "", }, preSelectedProviderNumber: { - type: [String, Number], + type: String, default: null, }, }, @@ -243,9 +207,6 @@ export default { showMoreShopsLinkText() { return this.getCmsContent("ShowMoreShopsLinkWidget", "Text"); }, - displayNoShopsAlert() { - return this.hasLoadedShopData && this.answers.length === 0; - }, }, methods: { openModal(event) { @@ -369,20 +330,22 @@ export default { this.shopIndex = 0; }, onModalOpened() { - this.shopIndex = 3; + const preSelectedIndex = this.shopProviders.findIndex( + (provider) => provider.providerNumber == this.preSelectedProviderNumber + ); + + if (preSelectedIndex > -1) { + this.shopIndex = Math.ceil((preSelectedIndex + 1) / 3) * 3; + } else { + this.shopIndex = 3; + } this.internalModel = this.copyModel(this.modelValue); this.internalModel.zipCode = this.zipCode; this.localShopProviderData = this.shopProviderData; this.answers = []; - this.updateShopsForZip(this.internalModel.zipCode); + this.onSearchZip(); this.focusOnZipInput(); this.selectedProviderNumber = this.preSelectedProviderNumber; - if (this.internalModel.zipCode && this.shopProviders.length > 0) { - this.updateShopsForZip(this.internalModel.zipCode); - } else { - this.internalModel.zipCode = this.zipCode; - this.updateShopsForZip(this.internalModel.zipCode); - } if ( (!this.selectedProviderNumber || !this.shopProviders.some( @@ -398,14 +361,7 @@ export default { }, onModalClosed() { this.internalModel = this.copyModel(this.modelValue); - this.selectedProviderNumber = this.preSelectedProviderNumber; this.resetsOnZipInput(); - let selectedProvider = this.shopProviders.find( - (provider) => provider.providerNumber == this.selectedProviderNumber - ); - if (!selectedProvider && this.shopProviders.length > 0) { - selectedProvider = this.shopProviders[0]; - } }, resetsOnZipInput() { this.resetAlerts(); @@ -415,33 +371,49 @@ export default { event.preventDefault(); event.stopPropagation(); } + this.resetsOnZipInput(); + this.displayNoShopsAlert = false; const zip = this.internalModel.zipCode; - if (this.isVehicleHeavyTruck) { - // check the location endpoint to verify this zip can service a heavy truck - const closestShops = await getClosestApplicableShops( - this.internalModel.zipCode, - this.carId, - "service-location" - ); - - if (!closestShops || closestShops.providers?.length === 0) { - this.displayNoServiceAlert = true; - this.focusOnZipInput(); - this.resetModalButtonStyle(); - return null; - } + const zipCodeData = await this.getZipCodeData( + this.internalModel.zipCode, + "service-location" + ); + if (!zipCodeData.isValid) { + this.displayInvalidZipAlert = true; + //this.selectedProviderNumber = null; + this.focusOnZipInput(); + this.resetModalButtonStyle(); } else { - getShopProviderData(zip).then(async (result) => { - this.localShopProviderData = result.data; - this.updateShopsForZip(this.internalModel.zipCode); - if (this.selectedAppointmentType === "Mobile") { - this.selectedProvider = new Provider( - this.shopProviderData.mobileProviderNumber - ); - } else { - this.selectedProvider = new Provider(); + if (this.isVehicleHeavyTruck) { + // check the location endpoint to verify this zip can service a heavy truck + const closestShops = await getClosestApplicableShops( + this.internalModel.zipCode, + this.carId, + "service-location" + ); + + if (!closestShops || closestShops.providers?.length === 0) { + this.displayNoServiceAlert = true; + this.focusOnZipInput(); + this.resetModalButtonStyle(); + return null; } - }); + } else { + getShopProviderData(zip).then(async (result) => { + if (this.displayNoShopsAlert === true) { + this.displayNoShopsAlert = false; + } + this.localShopProviderData = result.data; + this.updateShopsForZip(this.internalModel.zipCode); + if (this.selectedAppointmentType === "Mobile") { + this.selectedProvider = new Provider( + this.shopProviderData.mobileProviderNumber + ); + } else { + this.selectedProvider = new Provider(); + } + }); + } } }, async updateShopsForZip(zipCode) { @@ -458,11 +430,23 @@ export default { } this.isLoadingShops = true; if (!zipCode || !this.shopProviders.length) { - this.handleUpdate(); + this.answers = []; + this.displayNoShopsAlert = true; + this.displaySeeMoreLocationsLink = false; + this.isLoadingShops = false; return; } - const sortedShops = getShopsByZip(zipCode, this.shopProviders, 3); + const selectedIndex = this.shopProviders.findIndex( + (provider) => provider.providerNumber == this.selectedProviderNumber + ); + + // If not found, only show the first 3 shops + if (selectedIndex === -1) { + this.shopIndex = 3; + } + + const sortedShops = this.getShopsByZip(zipCode, this.shopProviders, this.shopIndex); const toTitleCase = (str) => { return str.replace(/\w\S*/g, function (txt) { @@ -498,12 +482,22 @@ export default { }; }); this.answers = mappedData; + if ( + this.selectedProviderNumber && + !this.answers.some((a) => String(a.value) === String(this.selectedProviderNumber)) + ) { + this.selectedProviderNumber = null; + } this.shopIndex = mappedData.length; this.displaySeeMoreLocationsLink = this.shopIndex < this.shopProviders.length; if (mappedData.length > 0) { this.lastSuccessfulZip = zipCode; } this.isLoadingShops = false; + this.displayNoShopsAlert = this.answers.length === 0; + }, + resetModalButtonStyle() { + this.modal.resetButtonStyle(); }, onInputIdAssigned(inputId) { this.serviceZipCodeTextInputId = inputId; @@ -515,17 +509,24 @@ export default { resetAlerts() { this.displayInvalidZipAlert = false; this.displayNoServiceAlert = false; + this.displayNoShopsAlert = false; }, - async SetZipCodeAndShop() { + async setZipCodeAndShop() { + if ( + this.displayInvalidZipAlert || + this.displayNoShopsAlert || + !this.selectedProviderNumber + ) { + return; + } + const zipToEmit = this.lastSearchedZip; + const selectedProvider = this.shopProviders.find( (provider) => provider.providerNumber == this.selectedProviderNumber ); this.resetAlerts(); - const zipCodeData = await this.getZipCodeData( - selectedProvider.address.zipCode, - "service-location" - ); + const zipCodeData = await this.getZipCodeData(zipToEmit, "service-location"); if (!zipCodeData.isValid) { this.displayInvalidZipAlert = true; @@ -548,7 +549,6 @@ export default { } } - selectedProvider.address.state = zipCodeData.state; selectedProvider.address.zipCodeCtu = zipCodeData.zipCodeCtu; // retrieve mobile fee part @@ -585,11 +585,25 @@ export default { this.$emit("update:modelValue", this.selectedValue); this.$emit("update-shop-provider-data", this.localShopProviderData); - this.$emit("shop-selected", selectedProvider); + this.internalModel.state = zipCodeData.state; + this.$emit("shop-selected", { + providerNumber: selectedProvider?.providerNumber, + address: selectedProvider?.address, + searchedZip: zipToEmit, + searchedState: this.internalModel.state, + }); this.closeModal(); } }, + getShopsByZip(zipCode, shops, numberToGet = 3) { + return shops + .filter( + (shop) => shop.address && shop.address.zipCode && shop.address.zipCode !== "" + ) + .sort((a, b) => a.distanceInMiles - b.distanceInMiles) + .slice(0, numberToGet); + }, }, watch: { shopProviderData: { @@ -597,14 +611,8 @@ export default { handler(newVal) { this.localShopProviderData = newVal; this.hasLoadedShopData = true; - if (this.internalModel && this.internalModel.zipCode) { - this.updateShopsForZip(this.internalModel.zipCode); - } }, }, - preSelectedProviderNumber(newVal) { - this.selectedProviderNumber = newVal; - }, }, components: { modal, @@ -613,9 +621,6 @@ export default { buttonQuestion, alert, }, - mounted() { - this.handleUpdate(); - }, }; @@ -658,7 +663,7 @@ export default { .modal.modal-component .modal-dialog .modal-content .modal-body .textbox-question { padding: 0; } -.zip-search-group { +.shop-question-zipcode { display: flex; flex-direction: row; align-items: stretch; @@ -673,44 +678,40 @@ export default { height: auto; padding-left: 0; } - .zip-search-input { + .input-wrapper.has-search-icon { + display: flex; align-items: stretch; flex: 1 1 0; height: 100%; margin-bottom: 0; - input { + input, + .form-control { width: 100%; - height: 100%; + height: 48px; + min-height: 48px; + max-height: 48px; border: none; - padding-top: 0; - padding-bottom: 0; + padding: 0 1.5rem 0 1.5rem; outline: none; font-size: 1rem; background: transparent; box-sizing: border-box; - border-radius: 48px 0 0 48px; - padding-left: 0; + border-radius: 2.5rem 0 0 2.5rem; } } - .btn { + .search-icon-button { display: flex; align-items: center; - background-color: #e5f1fa; justify-content: center; - width: 48px; + background-color: #e5f1fa !important; + width: 2.5rem; height: 48px; - border: none; - - border-radius: 0 48px 48px 0; + max-height: 48px; + border-radius: 0 2.5rem 2.5rem 0; cursor: pointer; } } -@media (max-width: 767.98px) { - .zip-search-group { - padding-left: 0; - } -} .show-more-shops-link a { text-align: center; display: block; @@ -732,4 +733,18 @@ export default { border-radius: 2.5rem; padding-left: 1.5rem; } + +.shop-question-zipcode .form-test-error { + display: block; + width: 100%; + margin-top: 0.25rem; + margin-left: 0; + color: #d32f2f; // or your error color + position: static !important; + font-size: 0.875rem; + clear: both; + float: none; + display: block; + width: 100%; +}