diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js
index f99ea660d..aa0643821 100644
--- a/src/constants/endpoints.js
+++ b/src/constants/endpoints.js
@@ -192,6 +192,10 @@ const endpoints = {
url: "/account/api/v1/account/bill-to-account-number",
method: "GET",
},
+ ClosestApplicableShops: {
+ url: "/location/api/v1/location/closest-applicable-shops",
+ method: "GET",
+ },
AddDonationPart: {
url: "/order/api/v1/order/add-donation-part",
method: "POST",
diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js
index 1e8945c49..7b76d4064 100644
--- a/src/constants/store-actions.js
+++ b/src/constants/store-actions.js
@@ -55,6 +55,7 @@ const storeActions = {
GET_INSURANCE_COMPANY_LIST: "getInsuranceCompanyList",
GET_BILL_TO_ACCOUNT_NUMBER: "getBillToAccountNumber",
GET_RECAL_PARTS_AND_SAVE_TO_LINE_ITEMS: "getRecalPartsAndSaveToLineItems",
+ GET_CLOSEST_APPLICABLE_SHOPS: "getClosestApplicableShops",
// Analytics
LOG_EXPERIMENT_EXPOSURE_AND_UPDATE_STORE: "logExperimentExposureAndUpdateStore",
diff --git a/src/constants/store-mutations.js b/src/constants/store-mutations.js
index 69e78138b..2f53d8133 100644
--- a/src/constants/store-mutations.js
+++ b/src/constants/store-mutations.js
@@ -9,6 +9,9 @@ const storeMutations = {
UPDATE_MAKE: "updateMake",
UPDATE_MODEL: "updateModel",
UPDATE_STYLE: "updateStyle",
+ UPDATE_VEHICLE_SUBTYPE: "updateVehicleSubType",
+ UPDATE_VEHICLE_SPECIAL_CLASS: "updateVehicleSpecialClass",
+ UPDATE_IS_BIGTRUCK: "updateIsBigTruck",
UPDATE_CAR_ID: "updateCarId",
UPDATE_VEHICLE_CATEGORY: "updateVehicleCategory",
UPDATE_VEHICLE_IMAGE_URL: "updateVehicleImageUrl",
@@ -16,6 +19,7 @@ const storeMutations = {
UPDATE_VEHICLE_IMAGE_COLOR: "updateVehicleImageColor",
UPDATE_VEHICLE_VIN: "updateVehicleVin",
UPDATE_VEHICLE: "updateVehicle",
+ UPDATE_VEHICLE_CAN_SAFELITE_SERVICE: "updateVehicleCanSafeliteService",
UPDATE_IS_REPAIR: "updateIsRepair",
UPDATE_NUMBER_OF_CHIPS: "updateNumberOfChips",
diff --git a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js
index 7a9ac00d0..106ed892c 100644
--- a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js
+++ b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js
@@ -149,6 +149,23 @@ export async function getAvailabilityRating(
return shopStatus;
}
+export async function getClosestApplicableShops(serviceZipCode, carId, pageNameToLog) {
+ if (!serviceZipCode) {
+ return null;
+ }
+
+ const closestShops = await baseMixin.methods.dispatchStoreActionWithLogging(
+ storeActions.GET_CLOSEST_APPLICABLE_SHOPS,
+ {
+ zip: serviceZipCode,
+ carId: carId,
+ },
+ pageNameToLog
+ );
+
+ return closestShops.data;
+}
+
export async function getZipCodeData(serviceZipCode) {
return await baseMixin.methods.getZipCodeData(serviceZipCode, "service-location");
}
diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue
index 56c76bb2d..a85a5bd17 100644
--- a/src/layouts/service-location/service-location.vue
+++ b/src/layouts/service-location/service-location.vue
@@ -15,6 +15,8 @@
editScreenReaderTextCmsWidgetName="ScreenReaderZipEditWidget"
v-model="serviceZipCodeQuestion"
ref="serviceZipCodeQuestion"
+ :carId="carId"
+ :isVehicleHeavyTruck="isVehicleHeavyTruck"
:mobileFeePart="mobileFeePart"
@updated-mobile-fee-part="setMobileFeePart"
@updated-recycle-fee-part="setRecycleFeePart"
@@ -186,9 +188,11 @@ export default {
return {
streetAddress: this.getServiceAddressFromStore(),
apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(),
+ carId: this.getCarIdfromStore(),
city: this.getServiceCityFromStore(),
state: this.getServiceStateFromStore(),
zipCode: this.getServiceZipCodeFromStore(),
+ isVehicleHeavyTruck: this.getIsVehicleHeavyTruckFromStore(),
isVehicleProtected: this.getIsVehicleProtectedFromStore(),
isGlassServiceableInshop: null,
isRecalibrationServiceableInshop: null,
@@ -514,6 +518,9 @@ export default {
});
}
},
+ getCarIdfromStore() {
+ return store.getters.vehicle.carId;
+ },
getServiceAddressFromStore() {
return store.getters.order.serviceLocation.address;
},
@@ -529,6 +536,9 @@ export default {
getServiceZipCodeFromStore() {
return store.getters.order.serviceLocation.zipCode;
},
+ getIsVehicleHeavyTruckFromStore() {
+ return store.getters.order.vehicle?.isBigTruck ?? false;
+ },
getIsVehicleProtectedFromStore() {
return store.getters.order.serviceLocation.isVehicleProtected;
},
diff --git a/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue b/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue
index a2ab4134e..5e7aa73e4 100644
--- a/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue
+++ b/src/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue
@@ -33,6 +33,13 @@
cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
+
@@ -48,6 +55,7 @@ import {
getPricedRecycleFeePart,
getServiceabilityDetails,
getBillToAccountNumber,
+ getClosestApplicableShops,
} from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
export default {
@@ -63,6 +71,7 @@ export default {
internalModel: this.copyModel(this.modelValue),
serviceZipCodeTextInputId: "",
displayInvalidZipAlert: false,
+ displayNoServiceAlert: false,
};
},
props: {
@@ -73,6 +82,11 @@ export default {
zipCode: "",
}),
},
+ carId: String,
+ isVehicleHeavyTruck: {
+ type: Boolean,
+ default: false,
+ },
mobileFeePart: {
type: Object,
default: () => ({}),
@@ -107,6 +121,7 @@ export default {
methods: {
resetAlerts() {
this.displayInvalidZipAlert = false;
+ this.displayNoServiceAlert = false;
},
resetsOnZipInput() {
this.resetAlerts();
@@ -155,6 +170,22 @@ export default {
this.focusOnZipInput();
this.resetModalButtonStyle();
} else {
+ 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;
+ }
+ }
+
this.internalModel.state = zipCodeData.state;
this.internalModel.zipCodeCtu = zipCodeData.zipCodeCtu;
diff --git a/src/layouts/service-location/shop-question/shop-question.vue b/src/layouts/service-location/shop-question/shop-question.vue
index 4a7818834..417a3b4c4 100644
--- a/src/layouts/service-location/shop-question/shop-question.vue
+++ b/src/layouts/service-location/shop-question/shop-question.vue
@@ -179,12 +179,12 @@ export default {
}
});
- this.pushEventToGA(
- this.GaCategories.SERVICE_LOCATION,
- gaAction,
- shops.join(","),
- true
- );
+ var joinedShops = shops.join(",");
+ if (!joinedShops) {
+ joinedShops = "no-shops";
+ }
+
+ this.pushEventToGA(this.GaCategories.SERVICE_LOCATION, gaAction, joinedShops, true);
}
if (this.answers.length === 0) {
diff --git a/src/layouts/vehicle/vehicle.vue b/src/layouts/vehicle/vehicle.vue
index 5f769b9b7..bad52fb02 100644
--- a/src/layouts/vehicle/vehicle.vue
+++ b/src/layouts/vehicle/vehicle.vue
@@ -48,6 +48,19 @@
validationRules="style-required"
placeHolderText="Select style"
customDropdownId="styleQuestionField" />
+
+
+
@@ -557,4 +636,9 @@ export default {
margin-top: 1.5rem;
margin-bottom: 0;
}
+.separator-line {
+ grid-area: 2/1/2/8;
+ border-top: 1px solid $gray-500;
+ margin: 0.5rem 0;
+}
diff --git a/src/store/index.js b/src/store/index.js
index 97a31068e..9fec43a77 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -66,9 +66,13 @@ const getDefaultState = () => {
make: null,
model: null,
style: null,
+ vehicleSubType: null,
+ vehicleSpecialClass: null,
+ isBigTruck: false,
carId: null,
category: null,
vin: null,
+ canSafeliteService: null,
imageUrl: null,
imageVifNumber: null,
imageColor: null,
@@ -216,12 +220,24 @@ export const mutations = {
updateStyle(state, style) {
state.order.vehicle.style = style;
},
+ updateVehicleSubType(state, vehicleSubType) {
+ state.order.vehicle.vehicleSubType = vehicleSubType;
+ },
+ updateVehicleSpecialClass(state, vehicleSpecialClass) {
+ state.order.vehicle.vehicleSpecialClass = vehicleSpecialClass;
+ },
+ updateIsBigTruck(state, isBigTruck) {
+ state.order.vehicle.isBigTruck = isBigTruck;
+ },
updateCarId(state, carId) {
state.order.vehicle.carId = carId;
},
updateVehicleCategory(state, category) {
state.order.vehicle.category = category;
},
+ updateVehicleCanSafeliteService(state, canSafeliteService) {
+ state.order.vehicle.canSafeliteService = canSafeliteService;
+ },
updateVehicleImageUrl(state, imageUrl) {
state.order.vehicle.imageUrl = imageUrl;
},
@@ -1248,6 +1264,15 @@ export const actions = {
});
},
+ getClosestApplicableShops(context, { payload: { zip, carId }, pageNameToLog }) {
+ return globalMethods.callHttpClient({
+ methods: endpoints.ClosestApplicableShops.method,
+ endpoint: `${endpoints.ClosestApplicableShops.url}/${zip}/${carId}`,
+ logApiCall: true,
+ pageNameToLog: pageNameToLog,
+ });
+ },
+
// Dependency Actions
resetVehicleStateAndDependencies(context) {
context.commit(storeMutations.RESET_VEHICLE_STATE);
@@ -1835,6 +1860,8 @@ export const actions = {
endPoint += `&${glassPieces}`;
}
+ endPoint += `&isHeavyTruckVehicle=${context.getters.order.vehicle.isBigTruck}`;
+
return globalMethods.callHttpClient({
method: endpoints.GetServiceabilityDetails.method,
endpoint: endPoint,
@@ -1861,6 +1888,8 @@ export const actions = {
if (windshieldPartWithRecal) {
url += `/${windshieldPartWithRecal.partNumber}`;
}
+ //heavy truck vehicle
+ url += `/${context.getters.order.vehicle.isBigTruck}`;
return globalMethods.callHttpClient({
method: endpoints.GetProviders.method,
@@ -2135,6 +2164,9 @@ export const actions = {
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
+ subType: vehicle.vehicleSubType,
+ specialClass: vehicle.vehicleSpecialClass,
+ isBigTruck: vehicle.isBigTruck,
isInsurance: order.payment.isInsurance ?? false,
isVerified: order.payment.insuranceCoverage.isVerified ?? false,
lineItems: {
@@ -2188,6 +2220,9 @@ export const actions = {
model: vehicle.model,
style: vehicle.style,
vin: vehicle.vin,
+ vehicleSubType: vehicle.vehicleSubType,
+ vehicleSpecialClass: vehicle.vehicleSpecialClass,
+ isBigTruck: vehicle.isBigTruck,
registration: {
firstName: vehicle.registration.firstName,
lastName: vehicle.registration.lastName,
@@ -2398,7 +2433,21 @@ export const actions = {
// Vehicle
saveVehicle(
context,
- { year, make, model, style, carId, category, imageUrl, imageVifNumber, imageVifColor }
+ {
+ year,
+ make,
+ model,
+ style,
+ vehicleSubType,
+ vehicleSpecialClass,
+ isBigTruck,
+ carId,
+ category,
+ canSafeliteService,
+ imageUrl,
+ imageVifNumber,
+ imageVifColor,
+ }
) {
if (
context.state.order.vehicle.year != year ||
@@ -2414,8 +2463,12 @@ export const actions = {
context.commit(storeMutations.UPDATE_MAKE, make);
context.commit(storeMutations.UPDATE_MODEL, model);
context.commit(storeMutations.UPDATE_STYLE, style);
+ context.commit(storeMutations.UPDATE_VEHICLE_SUBTYPE, vehicleSubType);
+ context.commit(storeMutations.UPDATE_VEHICLE_SPECIAL_CLASS, vehicleSpecialClass);
+ context.commit(storeMutations.UPDATE_IS_BIGTRUCK, isBigTruck);
context.commit(storeMutations.UPDATE_CAR_ID, carId);
context.commit(storeMutations.UPDATE_VEHICLE_CATEGORY, category);
+ context.commit(storeMutations.UPDATE_VEHICLE_CAN_SAFELITE_SERVICE, canSafeliteService);
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_URL, imageUrl);
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_VIF_NUMBER, imageVifNumber);
context.commit(storeMutations.UPDATE_VEHICLE_IMAGE_COLOR, imageVifColor);