diff --git a/src/layouts/contact-details/contact-details.vue b/src/layouts/contact-details/contact-details.vue index b864ff19..8222f36a 100644 --- a/src/layouts/contact-details/contact-details.vue +++ b/src/layouts/contact-details/contact-details.vue @@ -133,6 +133,7 @@ import errorMessages from '@/constants/error-messages'; import { required } from '@/helpers/validation-rules'; import widgetFields from '@/constants/cms-widget-fields'; import states from '@/constants/states'; +import applicationConfig from '@/constants/application-config'; // DEFINE VALIDATION RULES defineRule('street-address-required', required(errorMessages.SERVICE_ADDRESS_REQUIRED)); @@ -159,6 +160,7 @@ export default { next((vm) => { vm.setCmsContent(cmsContent); + vm.setupAddressLookup(); }); }, data() { @@ -239,7 +241,7 @@ export default { /** * @summary Steps to perform when forward button clicked. */ - forwardButtonAction() { + async forwardButtonAction() { const contactInfo = { notesForTechnician: this.notesForTechnician }; @@ -247,6 +249,8 @@ export default { const provider = useMainStore().serviceLocation.provider; + await this.geocodeAddress(); + useMainStore().updateServiceLocation({ address: this.address, address2: this.address2, @@ -267,7 +271,95 @@ export default { this.address = ''; this.address2 = ''; this.city = ''; - } + }, + setupAddressLookup() { + const apiKey = applicationConfig.GOOGLE_PLACES_API_KEY; + + this.$loadScript(`https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places&callback=Function.prototype`) + .catch(() => { + // Failed to fetch script + window.console.warn('Unable to load Google Places API script'); + }); + }, + geocodeAddress() { + const autoCompletePromise = new Promise((resolve, reject) => { + // Get Autocomplete Service + const acService = new window.google.maps.places.AutocompleteService(); + // Get Places Service, needs psuedo element (or a map) + const placeService = new window.google.maps.places.PlacesService(document.createElement('div')); + // Create Autocomplete Session token, multiple requests one pricing hit + const acSessionToken = new window.google.maps.places.AutocompleteSessionToken(); + + const addressValue = `${this.address}, ${this.city}, ${this.state} ${this.zipCode}`; + acService.getPlacePredictions( + { + input: addressValue, + type: ['geocode'], + componentRestrictions: { country: ['us'] }, + sessionToken: acSessionToken + }, + (predictions) => { + if (predictions && predictions.length > 0) { + const firstPrediction = predictions[0]; + if (firstPrediction.place_id) { + placeService.getDetails( + { + placeId: firstPrediction.place_id, + fields: ['address_components'], + sessionToken: acSessionToken + }, + (details) => { + this.fillInAddress(details); + resolve(); + } + ); + } else { + resolve(); + } + } else { + resolve(); + } + } + ); + }); + + return autoCompletePromise; + }, + async fillInAddress(googlePlace) { + let processedStreetAddress = false; + let processedRoute = false; + for (const component of googlePlace.address_components) { + const componentType = component.types[0]; + + switch (componentType) { + case 'street_number': { + if (processedRoute) { + this.address = `${component.long_name} ${this.address}`; + } else { + this.address = component.long_name; + } + + processedStreetAddress = true; + break; + } + case 'route': { + if (processedStreetAddress) { + this.address += ` ${component.short_name}`; + } else { + this.address = component.short_name; + } + + processedRoute = true; + break; + } + case 'locality': { + this.city = component.long_name; + break; + } + default: + } + } + }, } }; diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue index 90144474..41eee5ee 100644 --- a/src/layouts/payment-method/payment-method.vue +++ b/src/layouts/payment-method/payment-method.vue @@ -389,7 +389,6 @@ export default { } this.smsPhoneNumber = this.getSMSPhoneFromStore(); if (this.isPayInAdvanceDisabled) { - console.log('Pay in Advance is disabled, defaulting to Pay at Time of Service'); this.paymentMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE; } }, @@ -442,8 +441,11 @@ export default { handleEditClicked(section) { switch (section) { case 'location': + const scenario = this.mainStore.isMobileAppointment + ? this.navigationScenarios.EDIT_SERVICE_LOCATION_MOBILE + : this.navigationScenarios.EDIT_SERVICE_LOCATION_INSHOP; this.$router.navigateWithSpinner( - this.navigationScenarios.EDIT_SERVICE_LOCATION, + scenario, this.$route ); break; diff --git a/src/router/router-constants/navigation-scenarios.js b/src/router/router-constants/navigation-scenarios.js index bc9146fb..2c9768bf 100644 --- a/src/router/router-constants/navigation-scenarios.js +++ b/src/router/router-constants/navigation-scenarios.js @@ -105,7 +105,8 @@ const navigationScenarios = Object.freeze({ PAY_IN_ADVANCE_ERROR: 'PAY_IN_ADVANCE_ERROR', PAY_IN_ADVANCE_CREDIT_CARD_ERROR: 'PAY_IN_ADVANCE_CREDIT_CARD_ERROR', PAY_IN_ADVANCE_SUCCESS: 'PAY_IN_ADVANCE_SUCCESS', - EDIT_SERVICE_LOCATION: 'EDIT_SERVICE_LOCATION', + EDIT_SERVICE_LOCATION_INSHOP: 'EDIT_SERVICE_LOCATION_INSHOP', + EDIT_SERVICE_LOCATION_MOBILE: 'EDIT_SERVICE_LOCATION_MOBILE', EDIT_SCHEDULE: 'EDIT_SCHEDULE', EDIT_WIPERS: 'EDIT_WIPERS', diff --git a/src/router/router-constants/routing-table.js b/src/router/router-constants/routing-table.js index af06b4c6..8a45d37b 100644 --- a/src/router/router-constants/routing-table.js +++ b/src/router/router-constants/routing-table.js @@ -638,9 +638,13 @@ const routingTable = () => [ destinationIssPageValue: issPageValues.PAYMENT_PAGE }, { - scenario: navigationScenarios.EDIT_SERVICE_LOCATION, + scenario: navigationScenarios.EDIT_SERVICE_LOCATION_INSHOP, destinationIssPageValue: issPageValues.SCHEDULE_PAGE }, + { + scenario: navigationScenarios.EDIT_SERVICE_LOCATION_MOBILE, + destinationIssPageValue: issPageValues.CONTACT_DETAILS + }, { scenario: navigationScenarios.EDIT_SCHEDULE, destinationIssPageValue: issPageValues.SCHEDULE_PAGE