Merge branch 'release/heavy.truck' into rlsmerge/develop-to-heavy.truck
This commit is contained in:
commit
ef10fb3be7
18 changed files with 345 additions and 98 deletions
|
|
@ -5,6 +5,7 @@ const partNumberStrings = {
|
|||
DONATION: "DONATION",
|
||||
// Fees
|
||||
RECYCLE_FEE: "RECYCLE FEE",
|
||||
PRICING_BY_DAY_UPCHARGE: "PREMAPPT GEN",
|
||||
};
|
||||
|
||||
export { partNumberStrings };
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -9,9 +9,3 @@ const vehicleCategories = {
|
|||
};
|
||||
|
||||
export { vehicleCategories };
|
||||
|
||||
const vehicleSubTypes = {
|
||||
HEAVY_TRUCK: "HEAVY TRUCK",
|
||||
};
|
||||
|
||||
export { vehicleSubTypes };
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue