diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js
index c55410da..63ca9e2d 100644
--- a/src/constants/endpoints.js
+++ b/src/constants/endpoints.js
@@ -84,6 +84,10 @@ const endpoints = Object.freeze({
url: `${LOCATION_BASE_URL}/providers`,
method: 'GET'
},
+ GetTpaAndSafeliteProviders: {
+ url: `${LOCATION_BASE_URL}/tpa-and-safelite-providers`,
+ method: 'GET'
+ },
GetCapabilityQuestions: {
url: `${PARTS_BASE_URL}/capability-questions`,
method: 'GET'
diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js
index 71e7d515..868b8e13 100644
--- a/src/constants/error-messages.js
+++ b/src/constants/error-messages.js
@@ -60,7 +60,10 @@ const errorMessages = Object.freeze({
STYLE_REQUIRED: 'Vehicle style is required.',
MOBILE_LOCATION_REQUIRED: 'Please enter your service address',
DATE_REQUIRED: 'Please select a date',
- TIME_REQUIRED: 'Please select an appointment time.'
+ TIME_REQUIRED: 'Please select an appointment time.',
+ TPA_SEARCH_REQUIRED: 'Please enter a shop name or ZIP code.',
+ TPA_SEARCH_SHOP_FORMAT: 'Please enter a valid shop name.',
+ TPA_SEARCH_ZIP_FORMAT: 'Please enter a valid Zip code.'
});
export default errorMessages;
diff --git a/src/constants/global-rules.js b/src/constants/global-rules.js
index e82b118a..6dc75766 100644
--- a/src/constants/global-rules.js
+++ b/src/constants/global-rules.js
@@ -26,7 +26,8 @@ const globalRules = Object.freeze({
EXTENSION_FORMAT: 'extension-format',
ZIP_CODE_REQUIRED: 'zip-code-required',
ZIP_CODE_SEARCH_FORMAT: 'zip-code-search-format',
- OPTION_REQUIRED: 'option-required'
+ OPTION_REQUIRED: 'option-required',
+ TPA_SEARCH_FORMAT: 'tpa-search-format'
});
export default globalRules;
diff --git a/src/helpers/global-rule-definer.js b/src/helpers/global-rule-definer.js
index f5a2335b..227fc0bb 100644
--- a/src/helpers/global-rule-definer.js
+++ b/src/helpers/global-rule-definer.js
@@ -123,6 +123,28 @@ function defineGlobalZipCodeRules() {
defineRule(globalRules.ZIP_CODE_SEARCH_FORMAT, regex(/^\d{5}$/, errorMessages.ZIP_FORMAT));
}
+/**
+ * @summary Define global rules related to the zip code/shop name search on TPA Search page
+ */
+function defineGlobalTpaSearchRules() {
+ defineRule(globalRules.TPA_SEARCH_FORMAT, (value) => {
+ if (value.length === 0) {
+ return errorMessages.TPA_SEARCH_REQUIRED;
+ }
+ // Non Numeric
+ if (isNaN(value)) {
+ if (value.length < 3) {
+ return errorMessages.TPA_SEARCH_SHOP_FORMAT;
+ }
+ } else {
+ if (value.length != 5) {
+ return errorMessages.TPA_SEARCH_ZIP_FORMAT;
+ }
+ }
+ return true;
+ });
+}
+
/**
* @function defineGlobalRules
* @summary Define all global rules
@@ -136,6 +158,6 @@ export default function defineGlobalRules() {
defineGlobalPolicyNumberRules();
defineGlobalPolicyZipCodeRules();
defineGlobalZipCodeRules();
-
+ defineGlobalTpaSearchRules();
defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED));
}
diff --git a/src/layouts/tpa-search/tpa-search.vue b/src/layouts/tpa-search/tpa-search.vue
index 9476a7ad..2eed76f9 100644
--- a/src/layouts/tpa-search/tpa-search.vue
+++ b/src/layouts/tpa-search/tpa-search.vue
@@ -27,14 +27,14 @@
@@ -52,10 +52,10 @@
@invalidSubmit="onInvalidSubmit">
@@ -135,53 +135,8 @@ import widgetFields from '@/constants/cms-widget-fields.js';
import { shallowRef } from 'vue';
import { toTitleCase, toDisplayPhoneNumber } from '@/helpers/text-helper.js';
import bailoutMessage from '@/constants/bailoutMessage';
+import settleAllPromises from '@/helpers/layout-helper';
-const radiusFilterPairs = [
- { radius: 15, filter: '15 miles' },
- { radius: 25, filter: '25 miles' },
- { radius: 50, filter: '50 miles' },
- { radius: 100, filter: '100 miles' }
-];
-
-function convertRadiusFilterToInteger(filter) {
- const pair = radiusFilterPairs.find((p) => p.filter === filter);
- return pair?.radius ?? 0;
-}
-
-async function getInitialSearchData() {
- const customerZipCode = useMainStore().order.customer.address.zipCode;
- const serviceLocationZipCode = useMainStore().order.serviceLocation.zipCode;
- const zipCode = serviceLocationZipCode ?? customerZipCode;
-
- const { searchFilter } = useMainStore().order.serviceLocation;
- let { providerNumber } = useMainStore().order.serviceLocation.provider;
-
- let providers = [];
- let radius = 0;
- if (searchFilter) {
- radius = convertRadiusFilterToInteger(searchFilter);
- const result = await useMainStore().getTpaProviders(zipCode, radius);
- providers = result?.data?.shopProviders ?? [];
-
- return { zipCode, filter: searchFilter, providers, providerNumber };
- }
-
- providerNumber = null;
- let pairIndex = 0;
- let filter = '';
- while (providers.length === 0 && pairIndex < radiusFilterPairs.length) {
- const pair = radiusFilterPairs[pairIndex];
- radius = pair.radius;
- filter = pair.filter;
- // eslint-disable-next-line no-await-in-loop
- const result = await useMainStore().getTpaProviders(zipCode, radius);
- providers = result?.data?.shopProviders ?? [];
-
- pairIndex += 1;
- }
-
- return { zipCode, filter, providers, providerNumber };
-}
export default {
name: 'tpa-search',
@@ -200,23 +155,35 @@ export default {
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
- const { zipCode, filter, providers, providerNumber } =
- await getInitialSearchData();
- const cmsContent = await fetchCmsContentForPage(to.query.issPage);
-
+ const zipCode = useMainStore().order.customer.address.zipCode;
+ const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
+ const providersPromise = useMainStore().getTpaAndSafeliteProviders(zipCode);
+ const promiseResultMap = [
+ {
+ resultKey: 'cmsContent',
+ promise: cmsContentPromise
+ },
+ {
+ resultKey: 'providers',
+ promise: providersPromise
+ }
+ ];
+ const resultMap = await settleAllPromises(promiseResultMap);
next(async (vm) => {
- vm.setCmsContent(cmsContent);
- vm.setInitialSearchData(zipCode, filter, providers, providerNumber);
+ vm.setCmsContent(resultMap.cmsContent);
+ vm.tpaSearchValue = ""; // TODO: use page data to set the value
+ vm.mapZipCode = zipCode;
+ vm.providers = resultMap.providers;
});
},
data() {
return {
dataLoaded: false,
- zipCode: null,
+ tpaSearchValue: null,
mapZipCode: null,
- filter: '',
+ radiusFilter: useMainStore().order.serviceLocation.tpaSearchRadius ?? 25, // TODO: use page data to set the value
providers: [],
- selectedProviderNumber: '',
+ selectedProviderNumber: useMainStore().order.serviceLocation.provider.providerNumber,
reloadingProviders: false,
additionalButtonData: {
displayAvailabilityIndicators: false
@@ -231,7 +198,7 @@ export default {
siteFooter: 'SiteFooterWidget'
},
rules: {
- zipCode: `${globalRules.ZIP_CODE_REQUIRED}|${globalRules.ZIP_CODE_SEARCH_FORMAT}`,
+ tpaSearch: globalRules.TPA_SEARCH_FORMAT,
filter: globalRules.OPTION_REQUIRED, // TODO do we even need this?
provider: globalRules.OPTION_REQUIRED
},
@@ -239,17 +206,16 @@ export default {
};
},
computed: {
- filterOptions() {
- const filterByAnswers =
- this.getCmsContent(
+ radiusFilterOptions() {
+ const radiusFilterOptions = this.getCmsContent(
this.widget.filterByQuestion,
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
) ?? [];
- const filterByAnswersObj = {};
- [...filterByAnswers].forEach((answer) => {
- filterByAnswersObj[answer.Name] = answer.Name;
- });
- return filterByAnswersObj;
+ const options = {};
+ for (const option of radiusFilterOptions) {
+ options[option.Name] = option.Text;
+ }
+ return options;
},
tpaSearchQuestionLabel() {
return this.getCmsContent(
@@ -269,17 +235,17 @@ export default {
widgetFields.TEXT_BLOCK_WIDGET.TEXT
);
},
- radiusInMiles() {
- return convertRadiusFilterToInteger(this.filter);
- },
noNetworkShopsAlertHeaderText() {
return this.getCmsContent(
this.widget.noNetworkShopsAlert,
widgetFields.ALERT_WIDGET.HEADLINE_TEXT
)?.replaceAll('{custom:radiusInMiles}', this.radiusInMiles);
},
+ radiusFilteredAndCappedProviders() {
+ return this.providers.filter((provider) => provider.distanceInMiles <= this.radiusFilter).slice(0, 5);
+ },
providerAddresses() {
- return this.providers?.map((provider) => ({
+ return this.radiusFilteredAndCappedProviders?.map((provider) => ({
title: provider.companyName,
fullAddress: this.getFullProviderAddress(provider),
addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)]
@@ -287,7 +253,7 @@ export default {
},
providerButtonData() {
return (
- this.providers?.map((provider) =>
+ this.radiusFilteredAndCappedProviders?.map((provider) =>
this.getShopButtonDataFromProvider(provider)) ?? []
);
},
@@ -298,14 +264,6 @@ export default {
}
},
watch: {
- async filter() {
- if (this.dataLoaded) {
- await this.getProviderButtonData().then((providers) => {
- this.providers = providers;
- });
- this.mapZipCode = this.zipCode;
- }
- },
providers(newProviders) {
if (this.dataLoaded) {
this.selectedProviderNumber =
@@ -318,7 +276,7 @@ export default {
const provider = this.providers?.find((p) => p.providerNumber === newNumber);
if (provider && this.dataLoaded) {
useMainStore().updateServiceLocation({
- searchFilter: this.filter,
+ tpaSearchRadius: this.radiusFilter,
zipCode: this.zipCode,
provider: {
providerNumber: provider?.providerNumber,
@@ -342,13 +300,6 @@ export default {
}
},
methods: {
- setInitialSearchData(zipCode, filter, providers, providerNumber) {
- this.zipCode = zipCode;
- this.mapZipCode = zipCode;
- this.filter = filter;
- this.providers = providers;
- this.selectedProviderNumber = providerNumber;
- },
getFullProviderAddress(provider) {
const addressLine1 = this.getProviderAddress(provider);
const addressLine2 = this.getProviderCityZipState(provider);
@@ -379,14 +330,14 @@ export default {
}
return addressLine2;
},
- async getProviderButtonData() {
+ async getProviderButtonData(shopName = "") {
this.reloadingProviders = true;
- const getTpaProvidersResult = await useMainStore().getTpaProviders(
- this.zipCode,
- this.radiusInMiles
+ const getTpaProvidersResult = await useMainStore().getTpaAndSafeliteProviders(
+ this.mapZipCode,
+ shopName
);
this.reloadingProviders = false;
- return getTpaProvidersResult?.data?.shopProviders ?? [];
+ return getTpaProvidersResult?.data ?? [];
},
doNotSeeMyShopLinkClick() {
this.mainStore.setBailout(bailoutMessage.doNotSeeMyShop());
@@ -396,8 +347,12 @@ export default {
);
},
async searchClick() {
- this.providers = await this.getProviderButtonData();
- this.mapZipCode = this.zipCode;
+ if (isNaN(this.tpaSearchValue)) {
+ this.providers = await this.getProviderButtonData(this.tpaSearchValue);
+ } else {
+ this.mapZipCode = this.tpaSearchValue;
+ this.providers = await this.getProviderButtonData();
+ }
},
forwardButtonAction() {
if (this.selectedProviderIsSafeliteShop) {
@@ -409,14 +364,6 @@ export default {
.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP;
this.$router.navigate(scenario, this.$route);
},
- getCustomValueFromString(str) {
- switch (str) {
- case 'radiusInMiles':
- return this.radiusInMiles;
- default:
- return null;
- }
- },
getShopButtonDataFromProvider(provider) {
const cellNumber = toDisplayPhoneNumber(provider?.phoneNumber);
const distance =
diff --git a/src/store/index.js b/src/store/index.js
index 5fb37e57..48b73e89 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -142,7 +142,7 @@ export const getDefaultState = () => ({
appointmentType: null,
isVehicleProtected: null,
IsSafeliteProvider: null,
- searchFilter: null,
+ tpaSearchRadius: null,
provider: {
providerNumber: null,
address: {
@@ -1032,23 +1032,21 @@ export const useMainStore = defineStore({
});
},
- getTpaProviders(zipCode, radius) {
- const { carId, isBigTruck } = this.order.vehicle;
- const damageType = this.damage.isRepair ? 'Repair' : 'Replace';
+ getTpaAndSafeliteProviders(zipCode, provderNameSearchString = "") {
const { parentAccountNumber } = this.order;
- const partsWithRecal = getTopLevelGlassPartsWithRecal(this.order.lineItems.glassParts);
- const windshieldPartWithRecal = partsWithRecal?.length > 0 ? partsWithRecal[0] : null;
- const safeliteOnly = false;
+ const carId = this.order.vehicle.carId;
+ const damageType = this.damage.isRepair ? 'Repair' : 'Install';
+
+ const parts = getLineItemsFlattened(this.order.lineItems.glassParts);
+ const partNumbers = parts.map((part) => part.partNumber).join(',');
- let url = `${endpoints.GetProviders.url}/${zipCode}/${damageType}/${radius}/${parentAccountNumber}/${safeliteOnly}/${carId}`;
- if (windshieldPartWithRecal) {
- url += `/${windshieldPartWithRecal.partNumber}`;
+ let url = `${endpoints.GetTpaAndSafeliteProviders.url}/${zipCode}?accountNumber=${parentAccountNumber}&carId=${carId}&damageType=${damageType}&partNumbers=${partNumbers}`;
+ if (provderNameSearchString) {
+ url += `&providerNameSearchString=${provderNameSearchString}`;
}
- url += `/${isBigTruck}`;
-
return new Promise((resolve, reject) => {
globalMethods.callHttpClient({
- method: endpoints.GetProviders.method,
+ method: endpoints.GetTpaAndSafeliteProviders.method,
endpoint: url
}).then((response) => resolve(response), (error) => reject(error));
});
@@ -1822,7 +1820,7 @@ export const useMainStore = defineStore({
companyName: serviceLocationInfo.provider?.companyName,
phoneNumber: serviceLocationInfo.provider?.phoneNumber
};
- this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter;
+ this.order.serviceLocation.tpaSearchRadius = serviceLocationInfo.tpaSearchRadius;
},
resetState() {