Merge branch 'release/heavy.truck' into rlsmerge/develop-to-heavy.truck

This commit is contained in:
CarlNation 2025-04-04 06:38:41 -04:00
commit ef10fb3be7
18 changed files with 345 additions and 98 deletions

View file

@ -5,6 +5,7 @@ const partNumberStrings = {
DONATION: "DONATION",
// Fees
RECYCLE_FEE: "RECYCLE FEE",
PRICING_BY_DAY_UPCHARGE: "PREMAPPT GEN",
};
export { partNumberStrings };

View file

@ -8,8 +8,7 @@ const PREMIUM_TIME_SLOT_ID_FLAG = "-PREMIUM";
const PREMIUM_FEE_PART_TYPE = "EARLY BIRD";
// TODO; This will need updating with real PricingByDay part type
const PRICING_BY_DAY_PART_TYPE = "DISC CASHSAVE20";
const PRICING_BY_DAY_PART_TYPE = "PREMAPPT GEN";
const RouteCodeFlags = {
ALL_DAY_DROP_OFF: "ALL DAY DROP OFF",

View file

@ -10,6 +10,8 @@ const storeMutations = {
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",

View file

@ -9,9 +9,3 @@ const vehicleCategories = {
};
export { vehicleCategories };
const vehicleSubTypes = {
HEAVY_TRUCK: "HEAVY TRUCK",
};
export { vehicleSubTypes };

View file

@ -26,43 +26,36 @@ const DAYS_OF_WEEK = [
{
label: "Sunday",
cssClass: "sunday",
index: 0,
isPricingByDayUpchargeDay: false,
isPricingByDayUpchargeDay: true,
},
{
label: "Monday",
cssClass: "monday",
index: 1,
isPricingByDayUpchargeDay: true,
},
{
label: "Tuesday",
cssClass: "tuesday",
index: 2,
isPricingByDayUpchargeDay: false,
},
{
label: "Wednesday",
cssClass: "wednesday",
index: 3,
isPricingByDayUpchargeDay: false,
},
{
label: "Thursday",
cssClass: "thursday",
index: 4,
isPricingByDayUpchargeDay: false,
},
{
label: "Friday",
cssClass: "friday",
index: 5,
isPricingByDayUpchargeDay: true,
},
{
label: "Saturday",
cssClass: "saturday",
index: 6,
isPricingByDayUpchargeDay: true,
},
];

View file

@ -1,5 +1,7 @@
<template>
<div class="date-picker text-center" :class="`${calendarViewDirection} ${isPricingByDayClass}`">
<div
class="date-picker text-center"
:class="`${calendarViewDirection} ${isPricingByDayClass} ${showPricingByDayClass}`">
<fieldset id="date-picker-fieldset" ref="datePickerFieldset">
<legend class="sr-only">Select a day and time</legend>
<div
@ -60,6 +62,7 @@
date.dateNum === 1 ? 'first-day-' + month.startDateDayIndex : '',
date.dayClasses,
date.isSelectable ? 'selectable-day' : '',
date.isPricingByDayUpchargeDay ? 'upch-day' : '',
]">
<input
:disabled="!date.isSelectable"
@ -220,6 +223,9 @@ export default {
isPricingByDayClass() {
return this.isPricingByDayExperiment ? "pricing-by-day" : "";
},
showPricingByDayClass() {
return this.showPricingByDay ? "show-pricing-by-day" : "";
},
selectedDate: {
get() {
return this.modelValue;
@ -1143,8 +1149,8 @@ export default {
label {
background-color: $white;
border: none;
min-width: initial;
width: initial;
min-width: 100%;
width: 100%;
height: -webkit-fill-available;
border-radius: 0;
cursor: pointer;
@ -1163,6 +1169,35 @@ export default {
}
}
}
&.date-picker.show-pricing-by-day {
.radio-wrapper {
&.selectable-day label span {
text-decoration: none;
color: $gray-600;
font-weight: 400;
font-family: "AvertaSemibold";
&.price {
color: $green;
}
}
&.upch-day label span.price {
color: $gray-600;
font-weight: 400;
font-family: $font-family-sans-serif;
}
input[type="radio"] {
&:focus + label,
&:checked:focus + label {
color: $gray-600;
}
&:checked + label {
color: $blue;
}
}
}
}
}
.btn-link {

View file

@ -526,17 +526,9 @@ export default {
// try to call API to add donation to order
// TEMP DUMMY CALL TO SIMULATE SUCCESS OR ERROR FROM API CALL
// TO BE REPLACED BY REAL CALL LATER
const donationResponse = await this.dispatchStoreActionWithLogging(
storeActions.LOOKUP_VIN_BY_PLATE,
{ licensePlate: plateTemp, licenseState: "OH" },
"test",
false
).catch((error) => {
return error;
});
const donationResponse = this.createMockedResponse(amount);
if (donationResponse?.status == "200") {
if (donationResponse?.wasSuccessful) {
this.showDonationSuccess = true;
this.showDonationError = false;
const donationResponse = await baseMixin.methods.dispatchStoreAction(
@ -554,6 +546,26 @@ export default {
);
}
},
//mocked response. should be removed once integrate with actual api call.
createMockedResponse(amount) {
let result;
switch (amount) {
case 1:
result = { wasSuccessful: true, wasLocked: false };
break;
case 3:
result = { wasSuccessful: false, wasLocked: true };
break;
case 5:
result = { wasSuccessful: false, wasLocked: false };
break;
default:
result = { wasSuccessful: null, wasLocked: null }; // Default case if amount doesn't match
}
return result;
},
},
watch: {
donationAmount(newValue) {

View file

@ -54,7 +54,7 @@
:estimatedServiceMinutesMaximum="
selectableDatesData.estimatedServiceMinutesMaximum
"
@waitListRequested-emitted="handleWaitListRequested"
@waitListRequested="handleWaitListRequested"
@time-slot-modal-closed="timeSlotModalClosed"
validationRules="time-slot-selection-required"
@TimeSlotSelected="forwardButtonAction" />
@ -250,9 +250,15 @@ export default {
isRecalibrationOnOrder && shouldHideRecalibration
? getItemsWithoutRecalParts(lineItems.glassParts)
: (lineItems.glassParts ?? []);
const supportingItemsFromStore = lineItems?.supportingItems;
const supportingItemsWithoutFees = baseMixin.methods.filterOutCertainPartTypesOrNumbers(
lineItems.supportingItems,
{ partNumbersToRemove: [partNumberStrings.RECYCLE_FEE] }
{
partNumbersToRemove: [
partNumberStrings.RECYCLE_FEE,
partNumberStrings.PRICING_BY_DAY_UPCHARGE,
],
}
);
const lineItemsToBePriced = {
glassParts: glassParts,
@ -266,8 +272,8 @@ export default {
// Check to see if includePricingByDayUpcharge should already be set (based on order lineItems)
let includePricingByDayUpcharge = false;
if (supportingItemsWithoutFees) {
const pricingByDayUpchargeFeeIndex = supportingItemsWithoutFees.findIndex(
if (supportingItemsFromStore) {
const pricingByDayUpchargeFeeIndex = supportingItemsFromStore?.findIndex(
(item) => item.partType == PRICING_BY_DAY_PART_TYPE
);
if (pricingByDayUpchargeFeeIndex > -1) {
@ -300,7 +306,9 @@ export default {
});
// Get pricingByDayUpcharge needed for Pricing By Day
const pricingByDayUpchargePartPromise = getPricingByDayPartWithPrice();
const pricingByDayUpchargePartPromise = showPricingByDay
? getPricingByDayPartWithPrice()
: null;
const premiumFeePromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_MOBILE_PREMIUM_FEE,
@ -348,10 +356,12 @@ export default {
const resultMap = await settleAllPromises(promiseResultMap);
const pricingByDayUpcharge = await baseMixin.methods.getTotalLineItemPrice(
resultMap.pricingByDayUpchargePart,
false
);
const pricingByDayUpcharge = showPricingByDay
? await baseMixin.methods.getTotalLineItemPrice(
resultMap.pricingByDayUpchargePart,
false
)
: null;
const datePickerInitialData = resultMap.datePickerInitialData;
datePickerInitialData.pricingByDayBasePrice = pricingByDayBasePrice;
@ -620,24 +630,26 @@ export default {
const supportingItems = this.getSupportingItems();
// if we have a pricing by day upcharge, then save/update supporting items with it
const pricingByDayUpchargeFeeIndex = supportingItems?.findIndex(
(item) => item.partType == PRICING_BY_DAY_PART_TYPE
);
if (this.showPricingByDay) {
const pricingByDayUpchargeFeeIndex = supportingItems?.findIndex(
(item) => item.partType == PRICING_BY_DAY_PART_TYPE
);
if (this.includePricingByDayUpcharge) {
if (pricingByDayUpchargeFeeIndex > -1) {
supportingItems[pricingByDayUpchargeFeeIndex].laborAmount =
this.pricingByDayUpchargeLineItem.laborAmount;
supportingItems[pricingByDayUpchargeFeeIndex].sellingPrice =
this.pricingByDayUpchargeLineItem.sellingPrice;
supportingItems[pricingByDayUpchargeFeeIndex].kitPrice =
this.pricingByDayUpchargeLineItem.kitPrice;
if (this.includePricingByDayUpcharge) {
if (pricingByDayUpchargeFeeIndex > -1) {
supportingItems[pricingByDayUpchargeFeeIndex].laborAmount =
this.pricingByDayUpchargeLineItem.laborAmount;
supportingItems[pricingByDayUpchargeFeeIndex].sellingPrice =
this.pricingByDayUpchargeLineItem.sellingPrice;
supportingItems[pricingByDayUpchargeFeeIndex].kitPrice =
this.pricingByDayUpchargeLineItem.kitPrice;
} else {
supportingItems.push(this.pricingByDayUpchargeLineItem);
}
} else {
supportingItems.push(this.pricingByDayUpchargeLineItem);
}
} else {
if (pricingByDayUpchargeFeeIndex >= 0) {
supportingItems.splice(pricingByDayUpchargeFeeIndex, 1);
if (pricingByDayUpchargeFeeIndex >= 0) {
supportingItems.splice(pricingByDayUpchargeFeeIndex, 1);
}
}
}

View file

@ -43,8 +43,8 @@
v-if="waitListRequested"
class="mt-5 rounded waitlist-success"
ref="waitlistSuccessMessage">
<img :src="WaitListSuccessImage" class="success-image" />
<span v-html="WaitListSuccessText" class="success-text"></span>
<img :src="waitListSuccessImage" class="success-image" />
<span v-html="waitListSuccessText" class="success-text"></span>
</div>
<div
class="mt-5 mb-2 supplemental-information"
@ -366,10 +366,10 @@ export default {
displayWaitListFeature() {
return this.displayWaitList;
},
WaitListSuccessImage() {
waitListSuccessImage() {
return this.getCmsContent("WaitListSuccessWidget", "Image");
},
WaitListSuccessText() {
waitListSuccessText() {
return this.getCmsContent("WaitListSuccessWidget", "BodyText");
},
},
@ -539,7 +539,7 @@ export default {
};
},
waitListChecked(event) {
this.$emit("waitListRequested-emitted", event.target.checked);
this.$emit("waitListRequested", event.target.checked);
},
scrollToSuccessMessage() {
const successMessageElement = this.$refs.waitlistSuccessMessage;
@ -625,10 +625,10 @@ export default {
border: 1px solid #0c7e47;
border-radius: 5px;
font-size: $h5-font-size;
padding: 12px 16px;
margin-bottom: -8px;
padding: 0.75rem 1rem;
margin-bottom: -0.5rem;
.success-text {
margin-left: 8px;
margin-left: 0.5rem;
strong {
font-weight: 600;
letter-spacing: 0%;
@ -636,8 +636,8 @@ export default {
}
.success-image {
margin-top: 4.5px;
width: 16px;
height: 16px;
width: 1rem;
height: 1rem;
color: #0c7e47;
}
}

View file

@ -1,5 +1,6 @@
import { storeActions } from "@/constants/store-actions";
import baseMixin from "@/mixins/base-mixin.js";
import { partNumberStrings } from "@/constants/part-number-strings";
export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) {
if (!serviceZipCode) {
@ -42,6 +43,50 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) {
return pricingResults[0];
}
export async function getPricedRecycleFeePart(serviceZipCode, pageNameToLog) {
if (!serviceZipCode) {
return null;
}
const zipCodeData = await getZipCodeData(serviceZipCode);
// Get supporting items
const supportingItems = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_SUPPORTING_ITEMS,
null,
pageNameToLog,
false
);
if (
supportingItems.data === null ||
supportingItems.data === undefined ||
supportingItems.data === ""
) {
return null;
}
const recycleFeePart = supportingItems.data.find(
(item) => item.partNumber === partNumberStrings.RECYCLE_FEE
);
if (recycleFeePart) {
// Get the Recycle Fee Part Price
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
availableLineItems: [recycleFeePart],
serviceZipCode: serviceZipCode,
serviceZipCodeCtu: zipCodeData.zipCodeCtu,
},
pageNameToLog,
false
);
return pricingResults[0];
}
}
export async function getServiceabilityDetails(serviceZipCode, lineItems, pageNameToLog) {
// Get the Mobile Fee Part
return await baseMixin.methods.dispatchStoreActionWithLogging(
@ -104,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");
}

View file

@ -106,6 +106,23 @@ const mockGetPricedMobileFeePart = (mockServiceZipCode) => {
return Promise.resolve(mobileFeePart);
};
const mockGetPricedRecycleFeePart = (mockServiceZipCode) => {
let recycleFeePart = {};
if (mockServiceZipCode === "43235") {
recycleFeePart = {
partNumber: "RECYCLE FEE",
description: "RECYCLE FEE",
partType: "FEE",
laborAmount: 39.99,
sellingPrice: 0,
kitPrice: 0,
};
}
return Promise.resolve(recycleFeePart);
};
const mockGetServiceabilityDetails = (mockServiceZipCode) => {
const serviceabilityDetails = {
isGlassServiceableInshop: true,
@ -123,6 +140,9 @@ jest.mock(
getPricedMobileFeePart: jest.fn((mockServiceZipCode) => {
return mockGetPricedMobileFeePart(mockServiceZipCode);
}),
getPricedRecycleFeePart: jest.fn((mockServiceZipCode) => {
return mockGetPricedRecycleFeePart(mockServiceZipCode);
}),
getServiceabilityDetails: jest.fn((mockServiceZipCode) => {
return mockGetServiceabilityDetails(mockServiceZipCode);
}),

View file

@ -82,6 +82,7 @@ import vehicleProtectedQuestion from "@/layouts/service-location/mobile-location
import { deepClone } from "@/helpers/object-helper";
import {
getPricedMobileFeePart,
getPricedRecycleFeePart,
getServiceabilityDetails,
getBillToAccountNumber,
} from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
@ -267,6 +268,12 @@ export default {
"service-location"
);
// retrieve recycle fee part
const recycleFeePart = await getPricedRecycleFeePart(
serviceZipCode,
"service-location"
);
// retrieve serviceability details
const serviceabilityDetails = await getServiceabilityDetails(
serviceZipCode,
@ -280,6 +287,7 @@ export default {
// update content related to service zip code
this.$emit("updated-mobile-fee-part", mobileFeePart);
this.$emit("updated-recycle-fee-part", recycleFeePart);
this.$emit("updated-serviceability", serviceabilityDetails.data);
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu);

View file

@ -15,8 +15,11 @@
editScreenReaderTextCmsWidgetName="ScreenReaderZipEditWidget"
v-model="serviceZipCodeQuestion"
ref="serviceZipCodeQuestion"
:carId="carId"
:isVehicleHeavyTruck="isVehicleHeavyTruck"
:mobileFeePart="mobileFeePart"
@updated-mobile-fee-part="setMobileFeePart"
@updated-recycle-fee-part="setRecycleFeePart"
@updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase"
@updated-bill-to-account-number="setBillToAccountNumber"
@ -90,6 +93,7 @@
:mobileFeePart="mobileFeePart"
:mobileFeeApplies="mobileFeeApplies"
@updated-mobile-fee-part="setMobileFeePart"
@updated-recycle-fee-part="setRecycleFeePart"
@updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase"
@updated-mobile-ctu="setCtuForMobile"
@ -184,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,
@ -195,6 +201,7 @@ export default {
selectedAppointmentType: this.getSelectedAppointmentType(),
selectedProvider: this.getSelectedProvider(),
mobileFeePart: null,
recycleFeePart: null,
zipContainsMilitaryBase: false,
zipCodeCtu: null,
billToAccountNumber: null,
@ -480,6 +487,9 @@ export default {
setMobileFeePart(mobileFeePart) {
this.mobileFeePart = mobileFeePart;
},
setRecycleFeePart(recycleFeePart) {
this.recycleFeePart = recycleFeePart;
},
//creating async function as the computed property can not directly handle asynchronous operations or promises.
async setMobileLocationQuestions(newValue) {
var newZipCode = newValue.addressQuestions.zipCode;
@ -508,6 +518,9 @@ export default {
});
}
},
getCarIdfromStore() {
return store.getters.vehicle.carId;
},
getServiceAddressFromStore() {
return store.getters.order.serviceLocation.address;
},
@ -523,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;
},
@ -592,6 +608,7 @@ export default {
},
updateAndSaveSupportingItems() {
let supportingItems = store.getters.lineItems.supportingItems;
let shouldSaveSupportingItems = false;
supportingItems =
!supportingItems && this.isMobileStaticRecalibrationApplicable
@ -603,6 +620,21 @@ export default {
return;
}
// update recyle fee price
if (this.recycleFeePart) {
const recycleFeeIndex = supportingItems.findIndex(
(item) => item.partNumber == partNumberStrings.RECYCLE_FEE
);
if (recycleFeeIndex >= 0) {
supportingItems[recycleFeeIndex].laborAmount = this.recycleFeePart.laborAmount;
supportingItems[recycleFeeIndex].sellingPrice =
this.recycleFeePart.sellingPrice;
supportingItems[recycleFeeIndex].kitPrice = this.recycleFeePart.kitPrice;
shouldSaveSupportingItems = true;
}
}
// if we have a mobile fee, then save/update supporting items
if (this.selectedAppointmentType == "Mobile") {
const mobileFeeIndex = supportingItems.findIndex(
@ -617,11 +649,7 @@ export default {
if (this.mobileFeePart !== null) supportingItems.push(this.mobileFeePart);
}
this.dispatchStoreAction(
this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
supportingItems,
false
);
shouldSaveSupportingItems = true;
} else {
// if it's not a mobile, then make sure we remove any that may have been added
const removeMobileFeeIndex = supportingItems?.findIndex(
@ -630,13 +658,18 @@ export default {
if (removeMobileFeeIndex >= 0) {
supportingItems.splice(removeMobileFeeIndex, 1);
this.dispatchStoreAction(
this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
supportingItems,
false
);
shouldSaveSupportingItems = true;
}
}
// Use shouldSaveSupportingItems flag to determine if we need to save supporting items. Prevents unnecessary/multiple saves
if (shouldSaveSupportingItems) {
this.dispatchStoreAction(
this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
supportingItems,
false
);
}
},
async forwardButtonAction() {
this.navigatingForward = true;

View file

@ -32,6 +32,23 @@ const mockGetPricedMobileFeePart = (mockServiceZipCode) => {
return Promise.resolve(mobileFeePart);
};
const mockGetPricedRecycleFeePart = (mockServiceZipCode) => {
let recycleFeePart = {};
if (mockServiceZipCode === "43235") {
recycleFeePart = {
partNumber: "RECYCLE FEE",
description: "RECYCLE FEE",
partType: "FEE",
laborAmount: 39.99,
sellingPrice: 0,
kitPrice: 0,
};
}
return Promise.resolve(recycleFeePart);
};
const mockGetServiceabilityDetails = (mockServiceZipCode) => {
const serviceabilityDetails = {
isGlassServiceableInshop: true,
@ -49,6 +66,9 @@ jest.mock(
getPricedMobileFeePart: jest.fn((mockServiceZipCode) => {
return mockGetPricedMobileFeePart(mockServiceZipCode);
}),
getPricedRecycleFeePart: jest.fn((mockServiceZipCode) => {
return mockGetPricedRecycleFeePart(mockServiceZipCode);
}),
getServiceabilityDetails: jest.fn((mockServiceZipCode) => {
return mockGetServiceabilityDetails(mockServiceZipCode);
}),

View file

@ -33,6 +33,13 @@
cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<alert
ref="AlertNoService"
v-if="displayNoServiceAlert"
class="my-4"
cmsWidgetName="AlertNoServiceWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
</modal>
</template>
@ -45,8 +52,10 @@ import alert from "@/ux-components/alert/alert";
import {
getPricedMobileFeePart,
getPricedRecycleFeePart,
getServiceabilityDetails,
getBillToAccountNumber,
getClosestApplicableShops,
} from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
export default {
@ -62,6 +71,7 @@ export default {
internalModel: this.copyModel(this.modelValue),
serviceZipCodeTextInputId: "",
displayInvalidZipAlert: false,
displayNoServiceAlert: false,
};
},
props: {
@ -72,6 +82,11 @@ export default {
zipCode: "",
}),
},
carId: String,
isVehicleHeavyTruck: {
type: Boolean,
default: false,
},
mobileFeePart: {
type: Object,
default: () => ({}),
@ -106,6 +121,7 @@ export default {
methods: {
resetAlerts() {
this.displayInvalidZipAlert = false;
this.displayNoServiceAlert = false;
},
resetsOnZipInput() {
this.resetAlerts();
@ -154,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;
@ -164,6 +196,12 @@ export default {
"service-location"
);
// retrieve recycle fee part
const recycleFeePart = await getPricedRecycleFeePart(
serviceZipCode,
"service-location"
);
// retrieve serviceability details
const serviceabilityDetails = await getServiceabilityDetails(
serviceZipCode,
@ -177,6 +215,7 @@ export default {
// update content related to service zip code
this.$emit("updated-mobile-fee-part", mobileFeePart);
this.$emit("updated-recycle-fee-part", recycleFeePart);
this.$emit("updated-serviceability", serviceabilityDetails.data);
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
this.$emit("updated-bill-to-account-number", billToAccountNumber);

View file

@ -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) {

View file

@ -49,7 +49,7 @@
placeHolderText="Select style"
customDropdownId="styleQuestionField" />
<div v-if="isHeavyTruck">
<div v-if="isBigTruckAndCanService">
<div class="separator-line"></div>
<textboxQuestion
class="mb-4"
@ -110,7 +110,6 @@ import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
import { applicationConfig } from "../../constants/application-config";
import { queryStrings } from "@/constants/query-strings";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import { vehicleSubTypes } from "@/constants/vehicle-categories.js";
//define validation rules
defineRule("year-required", required(errorMessages.YEAR_REQUIRED));
@ -130,11 +129,11 @@ export default {
selectedStyle: this.selectedStylefromStore(),
carId: this.getCarIdfromStore(),
category: this.getCategoryfromStore(),
isBigTruck: this.getIsBigTruckfromStore(),
imageUrl: this.getImagefromStore(),
imageVifNumber: this.getImageVifNumberfromStore(),
imageVifColor: this.getImageVifColorfromStore(),
serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode,
vehicleSubType: this.getVehicleSubTypefromStore(),
yearOptions: [],
makeOptions: [],
modelOptions: [],
@ -325,7 +324,7 @@ export default {
this.selectedMake = null;
this.selectedModel = null;
this.selectedStyle = null;
this.vehicleSubType = null;
this.isBigTruck = false;
this.canSafeliteService = false;
this.carId = null;
if (year) {
@ -346,7 +345,7 @@ export default {
this.modelOptions = [];
this.selectedModel = null;
this.selectedStyle = null;
this.vehicleSubType = null;
this.isBigTruck = null;
this.carId = null;
if (make) {
const result = await this.getModelOptions(this.selectedYear, make);
@ -365,7 +364,7 @@ export default {
this.resetAlert();
this.styleOptions = [];
this.selectedStyle = null;
this.vehicleSubType = null;
this.isBigTruck = false;
this.carId = null;
if (model) {
const result = await this.getStyleOptions(
@ -430,8 +429,8 @@ export default {
!!this.carId
);
},
isHeavyTruck() {
return this.vehicleSubType === vehicleSubTypes.HEAVY_TRUCK && this.canSafeliteService;
isBigTruckAndCanService() {
return this.isBigTruck && this.canSafeliteService;
},
},
methods: {
@ -484,6 +483,8 @@ export default {
this.displayNoServiceAlert = !result?.data.canSafeliteService;
this.canSafeliteService = result?.data.canSafeliteService;
this.vehicleSubType = result?.data.vehicleSubType;
this.vehicleSpecialClass = result?.data.vehicleSpecialClass;
this.isBigTruck = result?.data.isBigTruck;
},
resetAlert() {
this.displayNoServiceAlert = false;
@ -498,6 +499,8 @@ export default {
model: this.selectedModel,
style: this.selectedStyle,
vehicleSubType: this.vehicleSubType,
vehicleSpecialClass: this.vehicleSpecialClass,
isBigTruck: this.isBigTruck,
carId: this.carId,
category: this.category,
canSafeliteService: this.canSafeliteService,
@ -508,7 +511,7 @@ export default {
false
);
if (this.isHeavyTruck) {
if (this.isBigTruck) {
const zipCodeData = await this.getZipCodeData(this.serviceZipCode);
await this.dispatchStoreAction(
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
@ -608,8 +611,8 @@ export default {
getImageVifColorfromStore() {
return store.getters.vehicle.imageVifColor;
},
getVehicleSubTypefromStore() {
return store.getters.vehicle.vehicleSubType;
getIsBigTruckfromStore() {
return store.getters.vehicle.isBigTruck;
},
},

View file

@ -51,7 +51,6 @@ import {
import { externalParameterStatus } from "@/constants/external-parameters";
import { experimentSettings } from "@/constants/experiments";
import experimentMixin from "@/mixins/experiment-mixin.js";
import { vehicleSubTypes } from "@/constants/vehicle-categories.js";
// Export State
const getDefaultState = () => {
@ -63,6 +62,8 @@ const getDefaultState = () => {
model: null,
style: null,
vehicleSubType: null,
vehicleSpecialClass: null,
isBigTruck: false,
carId: null,
category: null,
vin: null,
@ -217,6 +218,12 @@ export const mutations = {
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;
},
@ -729,7 +736,8 @@ export const mutations = {
// if we're loading a session and we do not have a provider number yet, then set isInsurance to null so that
// a service package is not selected by default on the quote page.
if (
!sessionInformation.order.payment.isInsurance &&
(sessionInformation.order.payment.isInsurance === null ||
sessionInformation.order.payment.isInsurance === undefined) &&
!sessionInformation.order.serviceLocation.provider?.providerNumber
) {
state.order.payment.isInsurance = null;
@ -846,9 +854,6 @@ export const getters = {
return false;
},
isHeavyTruckVehicle: (state) => {
return state.order.vehicle.vehicleSubType === vehicleSubTypes.HEAVY_TRUCK;
},
isMobileAppointment: (state) => {
return state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE;
},
@ -1848,7 +1853,7 @@ export const actions = {
endPoint += `&${glassPieces}`;
}
endPoint += `&isHeavyTruckVehicle=${context.getters.isHeavyTruckVehicle}`;
endPoint += `&isHeavyTruckVehicle=${context.getters.order.vehicle.isBigTruck}`;
return globalMethods.callHttpClient({
method: endpoints.GetServiceabilityDetails.method,
@ -1877,7 +1882,7 @@ export const actions = {
url += `/${windshieldPartWithRecal.partNumber}`;
}
//heavy truck vehicle
url += `/${context.getters.isHeavyTruckVehicle}`;
url += `/${context.getters.order.vehicle.isBigTruck}`;
return globalMethods.callHttpClient({
method: endpoints.GetProviders.method,
@ -2109,6 +2114,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: {
@ -2163,6 +2171,8 @@ export const actions = {
style: vehicle.style,
vin: vehicle.vin,
vehicleSubType: vehicle.vehicleSubType,
vehicleSpecialClass: vehicle.vehicleSpecialClass,
isBigTruck: vehicle.isBigTruck,
registration: {
firstName: vehicle.registration.firstName,
lastName: vehicle.registration.lastName,
@ -2379,6 +2389,8 @@ export const actions = {
model,
style,
vehicleSubType,
vehicleSpecialClass,
isBigTruck,
carId,
category,
canSafeliteService,
@ -2402,6 +2414,8 @@ export const actions = {
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);