Add map and some finishing touches to change location modal

This commit is contained in:
Alex Humphries 2026-01-09 17:20:56 -05:00
parent bcc156ec29
commit f3f99457f2
4 changed files with 78 additions and 24 deletions

View file

@ -163,7 +163,7 @@ export default {
&.dropdown-compact { &.dropdown-compact {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: end; justify-content: flex-end;
margin-bottom: 1.25rem; margin-bottom: 1.25rem;
.form-label { .form-label {
color: $darker-gray; color: $darker-gray;

View file

@ -107,9 +107,11 @@ export default {
async getBoundsFromAddress(address) { async getBoundsFromAddress(address) {
await this.setGeocoder(); await this.setGeocoder();
const result = await this.geocoder.geocode({ address }); const result = await this.geocoder.geocode({ address });
return result?.results?.length > 0 if (result?.results?.length > 0) {
? result.results[0].geometry?.bounds return result.results[0].geometry?.bounds ?? null;
: null; } else {
return null;
}
}, },
async createMapWithMarkersForAddresses(markers) { async createMapWithMarkersForAddresses(markers) {
const markerPositions = await this.getLocationsFromAddresses(markers); const markerPositions = await this.getLocationsFromAddresses(markers);
@ -117,9 +119,12 @@ export default {
const map = await this.getMap(zipBounds?.getCenter()); const map = await this.getMap(zipBounds?.getCenter());
await this.addMarkersToMap(map, markerPositions); await this.addMarkersToMap(map, markerPositions);
let positionsToDisplay = markerPositions.map((marker) => marker.position);
if(zipBounds) {
positionsToDisplay.push(zipBounds.getNorthEast());
positionsToDisplay.push(zipBounds.getSouthWest());
}
const positionsToDisplay = markerPositions.map((marker) => marker.position)
.concat(zipBounds?.getNorthEast(), zipBounds?.getSouthWest());
const bounds = this.getBounds(positionsToDisplay); const bounds = this.getBounds(positionsToDisplay);
map.fitBounds(bounds); map.fitBounds(bounds);
} }

View file

@ -42,12 +42,8 @@ export default {
methods: { methods: {
updateModelValue() { updateModelValue() {
this.$emit('update:modelValue', this.internalZipcode); this.$emit('update:modelValue', this.internalZipcode);
this.internalZipcode = '';
}, },
},
watch: {
modelValue(newValue) {
this.internalZipcode = newValue;
}
} }
}; };
</script> </script>

View file

@ -19,9 +19,9 @@
<span class="shop-name">{{ displayedShopName }}</span> <span class="shop-name">{{ displayedShopName }}</span>
<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">{{ toTitleCase(modelValue.address?.streetAddress) }}</div> <div class="address-line">{{ getProviderAddress(modelValue) }}</div>
<div class="address-line"> <div class="address-line">
{{ toTitleCase(modelValue.address?.city) }}, {{ modelValue.address?.state }} {{ modelValue.address?.zipCode }} {{ getProviderCityZipState(modelValue) }}
</div> </div>
</div> </div>
<buttonMain <buttonMain
@ -36,6 +36,11 @@
:footerButtonText="modalFooterText" :footerButtonText="modalFooterText"
:modalPosition="modalPositions.center" :modalPosition="modalPositions.center"
@footerButtonEvent="updateSelectedProvider"> @footerButtonEvent="updateSelectedProvider">
<googleMap
id="map"
class="mb-4"
:markers="providerAddresses"
:zipCode="internalZipcode" />
<dropdownQuestion <dropdownQuestion
inputId="searchRadiusDropdown" inputId="searchRadiusDropdown"
ref="searchRadiusQuestion" ref="searchRadiusQuestion"
@ -59,6 +64,7 @@
{{ serviceZipPrompt }} {{ serviceZipPrompt }}
</span> </span>
<serviceZipQuestion <serviceZipQuestion
v-if="renderServiceZip"
ref="serviceZipCodeQuestion" ref="serviceZipCodeQuestion"
v-model="internalZipcode" v-model="internalZipcode"
customInputId="serviceZipCode" customInputId="serviceZipCode"
@ -84,11 +90,12 @@ import serviceZipQuestion from '@/layouts/service-location/service-zip-question/
import buttonQuestion from '@/digital-components/button-question/button-question.vue'; import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue'; import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue';
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue'; import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
import googleMap from '@/iss-components/google-map/google-map.vue';
// Supporting files // Supporting files
import baseMixin from '@/mixins/base-mixin.js'; import baseMixin from '@/mixins/base-mixin.js';
import { toTitleCase } from '@/helpers/text-helper.js'; import { toTitleCase } from '@/helpers/text-helper.js';
import { markRaw, nextTick } from 'vue'; import { markRaw } from 'vue';
import { getServiceabilityDetails, getZipCodeData,getAvailabilityRating } from '@/helpers/service-location-helper'; import { getServiceabilityDetails, getZipCodeData,getAvailabilityRating } from '@/helpers/service-location-helper';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import widgetFields from '@/constants/cms-widget-fields'; import widgetFields from '@/constants/cms-widget-fields';
@ -103,7 +110,8 @@ export default {
modal, modal,
serviceZipQuestion, serviceZipQuestion,
buttonQuestion, buttonQuestion,
dropdownQuestion dropdownQuestion,
googleMap
}, },
mixins: [baseMixin], mixins: [baseMixin],
props: { props: {
@ -116,7 +124,7 @@ export default {
validationRules: String, validationRules: String,
isDisplayed: Boolean, isDisplayed: Boolean,
modalWidgetName: String, modalWidgetName: String,
selectedAppointmentType: String selectedAppointmentType: String,
}, },
data() { data() {
return { return {
@ -132,7 +140,8 @@ export default {
searchRadiusInMiles: 100, searchRadiusInMiles: 100,
nearbyShops: [], nearbyShops: [],
modalPositions, modalPositions,
dropdownVariants dropdownVariants,
renderServiceZip: true
}; };
}, },
emits: ['update:modelValue'], emits: ['update:modelValue'],
@ -179,16 +188,13 @@ export default {
}, },
nearbyShopsData() { nearbyShopsData() {
return this.nearbyShops.map((shopProvider) => { return this.nearbyShops.map((shopProvider) => {
const streetAddress = toTitleCase(shopProvider.address.streetAddress);
const city = toTitleCase(shopProvider.address.city); const city = toTitleCase(shopProvider.address.city);
const { state } = shopProvider.address;
const { zipCode } = shopProvider.address;
const distanceInMiles = shopProvider.distanceInMiles.toFixed(2); const distanceInMiles = shopProvider.distanceInMiles.toFixed(2);
return { return {
buttonLabel: city, buttonLabel: city,
buttonLabelSubCopy: `${distanceInMiles} mi`, buttonLabelSubCopy: `${distanceInMiles} mi`,
buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`, buttonBodyCopy: this.getFullProviderAddress(shopProvider),
value: shopProvider.providerNumber value: shopProvider.providerNumber
}; };
}); });
@ -200,11 +206,18 @@ export default {
optionsObj[option.Name] = option.Text; optionsObj[option.Name] = option.Text;
}); });
return optionsObj; return optionsObj;
} },
providerAddresses() {
return this.nearbyShops?.map((provider) => ({
title: toTitleCase(provider.companyName),
fullAddress: this.getFullProviderAddress(provider),
addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)]
})) ?? [];
},
}, },
watch: { watch: {
internalZipcode() { async internalZipcode() {
this.refreshShops(); await this.resetsOnZipInput();
}, },
async searchRadiusInMiles() { async searchRadiusInMiles() {
this.nearbyShops = await this.getNearbyShops(this.searchRadiusInMiles); this.nearbyShops = await this.getNearbyShops(this.searchRadiusInMiles);
@ -230,6 +243,7 @@ export default {
this.resetsOnZipInput().then(() => { this.resetsOnZipInput().then(() => {
this.internalProviderNumber = this.nearbyShops[0]?.providerNumber; this.internalProviderNumber = this.nearbyShops[0]?.providerNumber;
}); });
this.forceServiceZipRerender();
}, },
onModalClosed() { onModalClosed() {
this.internalZipcode = this.serviceZipcode; this.internalZipcode = this.serviceZipcode;
@ -249,6 +263,42 @@ export default {
async getNearbyShops(radiusInMiles) { async getNearbyShops(radiusInMiles) {
const result = await useMainStore().getProviders(this.internalZipcode, radiusInMiles); const result = await useMainStore().getProviders(this.internalZipcode, radiusInMiles);
return result.data.shopProviders; 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; color: $black;
font-weight: 600; font-weight: 600;
} }
:deep(#map) {
height: 27rem;
}
} }
</style> </style>