Merge branch 'develop' into feature/CSR-886
This commit is contained in:
commit
987db9bb61
17 changed files with 737 additions and 230 deletions
|
|
@ -26,7 +26,7 @@ module.exports = {
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
statements: 80,
|
statements: 78,
|
||||||
// Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90
|
// Got the go ahead from Mark to temporarily lower this. Taking out initialize component made the year,make,model and style coverage drop a bit. Once unit tests for license plate lookup, vin lookup and address lookup are in the coverage should go back up to 90
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -108,12 +108,14 @@ const endpoints = {
|
||||||
},
|
},
|
||||||
GetShopTimeSlots: {
|
GetShopTimeSlots: {
|
||||||
url: "/schedule/api/v1/schedule/shop-time-slots",
|
url: "/schedule/api/v1/schedule/shop-time-slots",
|
||||||
mockUrl: "https://mockey.qa.sagaws.net/service/shop-time-slots", // TODO: REMOVE MOCKURL
|
method: "POST",
|
||||||
|
},
|
||||||
|
GetMobileTimeSlots: {
|
||||||
|
url: "/schedule/api/v1/schedule/mobile-time-slots",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
GetMobileEarlyBirdFee: {
|
GetMobileEarlyBirdFee: {
|
||||||
url: "/parts/api/v1/parts/mobile-early-bird-fee",
|
url: "/parts/api/v1/parts/mobile-early-bird-fee",
|
||||||
mockUrl: "https://mockey.qa.sagaws.net/service/mobile-early-bird-fee", // TODO: REMOVE MOCKURL
|
|
||||||
method: "GET",
|
method: "GET",
|
||||||
},
|
},
|
||||||
SaveSession: {
|
SaveSession: {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ const experimentUniverses = {
|
||||||
const experimentSettings = {
|
const experimentSettings = {
|
||||||
GOOGLE_CUSTOM_DIMENSION_INDEX: "Google Custom Dimension Index",
|
GOOGLE_CUSTOM_DIMENSION_INDEX: "Google Custom Dimension Index",
|
||||||
SUPPRESS_VIN_CAPTURE: "SuppressVinCapture",
|
SUPPRESS_VIN_CAPTURE: "SuppressVinCapture",
|
||||||
|
DISPLAY_AVAILABILITY_INDICATORS: "DisplayAvailabilityIndicators",
|
||||||
};
|
};
|
||||||
|
|
||||||
const experimentTriggers = {
|
const experimentTriggers = {
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ const storeActions = {
|
||||||
GET_MOBILE_FEE_PART: "getMobileFeePart",
|
GET_MOBILE_FEE_PART: "getMobileFeePart",
|
||||||
GET_SERVICEABILITY_DETAILS: "getServiceabilityDetails",
|
GET_SERVICEABILITY_DETAILS: "getServiceabilityDetails",
|
||||||
GET_SHOP_TIME_SLOTS: "getShopTimeSlots",
|
GET_SHOP_TIME_SLOTS: "getShopTimeSlots",
|
||||||
|
GET_MOBILE_TIME_SLOTS: "getMobileTimeSlots",
|
||||||
GET_PROVIDERS: "getProviders",
|
GET_PROVIDERS: "getProviders",
|
||||||
GET_MOBILE_EARLY_BIRD_FEE: "getMobileEarlyBirdFee",
|
GET_MOBILE_EARLY_BIRD_FEE: "getMobileEarlyBirdFee",
|
||||||
SAVE_SESSION: "saveSession",
|
SAVE_SESSION: "saveSession",
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,9 @@ export default {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
modelValue(newValue, oldValue) {
|
modelValue(newValue, oldValue) {
|
||||||
this.resetField();
|
this.resetField({
|
||||||
|
value: newValue,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
answers() {
|
answers() {
|
||||||
//once we get the answers to display from parent, see if we need a GA event to log what we showed
|
//once we get the answers to display from parent, see if we need a GA event to log what we showed
|
||||||
|
|
|
||||||
|
|
@ -290,9 +290,10 @@ export default {
|
||||||
|
|
||||||
let myPromise = new Promise((resolve, reject) => {
|
let myPromise = new Promise((resolve, reject) => {
|
||||||
const response = config.customSelectableDatesCallback(
|
const response = config.customSelectableDatesCallback(
|
||||||
initialViewStartDate,
|
initialViewStartDate.toISOString().split("T")[0],
|
||||||
initialViewEndDate,
|
initialViewEndDate.toISOString().split("T")[0],
|
||||||
store.getters.order.serviceLocation.appointmentType
|
store.getters.order.serviceLocation.appointmentType,
|
||||||
|
store.getters.order.serviceLocation.provider.providerNumber
|
||||||
);
|
);
|
||||||
resolve(response);
|
resolve(response);
|
||||||
});
|
});
|
||||||
|
|
@ -354,7 +355,6 @@ export default {
|
||||||
this.hideSomeDaysForInitialView = config.hideSomeDaysForInitialView;
|
this.hideSomeDaysForInitialView = config.hideSomeDaysForInitialView;
|
||||||
const hideSecondMonth = config.hideSecondMonth;
|
const hideSecondMonth = config.hideSecondMonth;
|
||||||
const direction = config.calendarViewDirection;
|
const direction = config.calendarViewDirection;
|
||||||
|
|
||||||
const monthsAfterToLoadOffset = 12;
|
const monthsAfterToLoadOffset = 12;
|
||||||
const monthsBeforeToLoadOffset = 36;
|
const monthsBeforeToLoadOffset = 36;
|
||||||
config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
|
config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
|
||||||
|
|
@ -571,7 +571,8 @@ export default {
|
||||||
const moreSelectableDates = await this.customSelectableDatesCallback(
|
const moreSelectableDates = await this.customSelectableDatesCallback(
|
||||||
monthStart,
|
monthStart,
|
||||||
monthEnd,
|
monthEnd,
|
||||||
this.$store.getters.order.serviceLocation.appointmentType
|
this.$store.getters.order.serviceLocation.appointmentType,
|
||||||
|
this.$store.getters.order.serviceLocation.provider.providerNumber
|
||||||
);
|
);
|
||||||
moreSelectableDates.days.forEach((selectableDate) => {
|
moreSelectableDates.days.forEach((selectableDate) => {
|
||||||
const index = this.selectableDatesData.findIndex(
|
const index = this.selectableDatesData.findIndex(
|
||||||
|
|
|
||||||
|
|
@ -81,18 +81,33 @@ import store from "@/store";
|
||||||
defineRule("date-required", required(errorMessages.DATE_REQUIRED));
|
defineRule("date-required", required(errorMessages.DATE_REQUIRED));
|
||||||
defineRule("time-slot-selection-required", required(errorMessages.DATE_REQUIRED));
|
defineRule("time-slot-selection-required", required(errorMessages.DATE_REQUIRED));
|
||||||
|
|
||||||
const getAvailableDates = async (startDate, endDate, appointmentType) => {
|
const getAvailableDates = async (startDate, endDate, appointmentType, providerNumber) => {
|
||||||
// USING DATES PASSED, MAKE AN API CALL
|
// USING DATES PASSED, MAKE AN API CALL
|
||||||
const newShopTimeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
|
|
||||||
|
let newTimeSlotsResponse;
|
||||||
|
if (appointmentType === AppointmentTypeStrings.MOBILE) {
|
||||||
|
newTimeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.GET_MOBILE_TIME_SLOTS,
|
||||||
|
{
|
||||||
|
startDate: startDate,
|
||||||
|
endDate: endDate,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
newTimeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
|
||||||
storeActions.GET_SHOP_TIME_SLOTS,
|
storeActions.GET_SHOP_TIME_SLOTS,
|
||||||
{
|
{
|
||||||
startDate: startDate,
|
startDate: startDate,
|
||||||
endDate: endDate,
|
endDate: endDate,
|
||||||
shopAppointmentType: appointmentType,
|
shopAppointmentType: appointmentType,
|
||||||
|
providerNumber: providerNumber,
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
const newShopTimeSlots = newShopTimeSlotsResponse.data;
|
}
|
||||||
|
|
||||||
|
const newShopTimeSlots = newTimeSlotsResponse.data;
|
||||||
return convertApiResponse(newShopTimeSlots);
|
return convertApiResponse(newShopTimeSlots);
|
||||||
};
|
};
|
||||||
const convertApiResponse = (responseData) => {
|
const convertApiResponse = (responseData) => {
|
||||||
|
|
@ -112,9 +127,9 @@ export default {
|
||||||
name: "schedule",
|
name: "schedule",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedDate: null,
|
selectedDate: this.getSelectedDate(),
|
||||||
selectedTimeSlotData: {
|
selectedTimeSlotData: {
|
||||||
id: null,
|
id: this.getSelectedRouteCode(),
|
||||||
isPremiumAppointment: null,
|
isPremiumAppointment: null,
|
||||||
},
|
},
|
||||||
selectableDatesData: [],
|
selectableDatesData: [],
|
||||||
|
|
@ -152,7 +167,6 @@ export default {
|
||||||
const alertReasonsPromise = locationAlerts.methods.loadInitialData(
|
const alertReasonsPromise = locationAlerts.methods.loadInitialData(
|
||||||
store.getters.order.serviceLocation.zipCodeCtu
|
store.getters.order.serviceLocation.zipCodeCtu
|
||||||
);
|
);
|
||||||
|
|
||||||
// Settle promises and get results
|
// Settle promises and get results
|
||||||
const promiseResultMap = [
|
const promiseResultMap = [
|
||||||
{
|
{
|
||||||
|
|
@ -205,7 +219,7 @@ export default {
|
||||||
if (this.selectedDate === null) {
|
if (this.selectedDate === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.selectableDatesData.days.find(
|
return this.selectableDatesData.days?.find(
|
||||||
(selectableDate) => selectableDate.dateString === this.selectedDate.dateString
|
(selectableDate) => selectableDate.dateString === this.selectedDate.dateString
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -216,12 +230,14 @@ export default {
|
||||||
const timeSlotSelectedObject = this.getTimeSlotObjectFromTimeSlotId(
|
const timeSlotSelectedObject = this.getTimeSlotObjectFromTimeSlotId(
|
||||||
this.selectedTimeSlotData.id
|
this.selectedTimeSlotData.id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (timeSlotSelectedObject) {
|
if (timeSlotSelectedObject) {
|
||||||
return {
|
return {
|
||||||
date: this.selectedDate.dateString,
|
date: this.selectedDate.dateString,
|
||||||
startTime: timeSlotSelectedObject.startTime,
|
startTime: timeSlotSelectedObject.startTime,
|
||||||
endTime: timeSlotSelectedObject.endTime,
|
endTime: timeSlotSelectedObject.endTime,
|
||||||
id: this.selectedTimeSlotData.id,
|
routeCode: this.selectedTimeSlotData.id,
|
||||||
|
jobMaxMinutes: this.selectableDatesData.estimatedServiceMinutesMaximum,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -241,7 +257,8 @@ export default {
|
||||||
const newShopTimeSlots = await getAvailableDates(
|
const newShopTimeSlots = await getAvailableDates(
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
this.appointmentType
|
this.appointmentType,
|
||||||
|
this.$store.getters.order.serviceLocation.provider.providerNumber
|
||||||
);
|
);
|
||||||
// ADD API CALL RESULTS TO EXISTING DATE DATA
|
// ADD API CALL RESULTS TO EXISTING DATE DATA
|
||||||
this.selectableDatesData.days = this.selectableDatesData.days.concat(
|
this.selectableDatesData.days = this.selectableDatesData.days.concat(
|
||||||
|
|
@ -261,8 +278,14 @@ export default {
|
||||||
).timeSlots;
|
).timeSlots;
|
||||||
return timeSlots.find((timeSlot) => timeSlot.id === timeSlotId);
|
return timeSlots.find((timeSlot) => timeSlot.id === timeSlotId);
|
||||||
},
|
},
|
||||||
|
getSelectedDate() {
|
||||||
|
return store.getters.order.schedule.date;
|
||||||
|
},
|
||||||
|
getSelectedRouteCode() {
|
||||||
|
return store.getters.order.schedule.routeCode;
|
||||||
|
},
|
||||||
timeSlotModalClosed() {
|
timeSlotModalClosed() {
|
||||||
// Clear the selectedDate if no timeslot has been selected
|
// Clear the selectedDate if no timeSlot has been selected
|
||||||
if (!this.selectedTimeSlotData.id) {
|
if (!this.selectedTimeSlotData.id) {
|
||||||
this.selectedDate = null;
|
this.selectedDate = null;
|
||||||
}
|
}
|
||||||
|
|
@ -302,13 +325,14 @@ export default {
|
||||||
convertSelectedDateToShortMonthAndDay(selectedDate) {
|
convertSelectedDateToShortMonthAndDay(selectedDate) {
|
||||||
// This conversion ensures we don't get get GMT induced date changes
|
// This conversion ensures we don't get get GMT induced date changes
|
||||||
const dateObject = new Date(`${selectedDate.dateString}T00:00:00`);
|
const dateObject = new Date(`${selectedDate.dateString}T00:00:00`);
|
||||||
|
// Ex: April 25
|
||||||
return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" });
|
return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" });
|
||||||
},
|
},
|
||||||
// Expected input: "HH:MM:SS"
|
// Expected input: "HH:MM"
|
||||||
getDisplayTextForMilitaryTime(militaryTimeInput, shouldTrimMinutesIfEmpty = false) {
|
getDisplayTextForMilitaryTime(militaryTimeInput, shouldTrimMinutesIfEmpty = false) {
|
||||||
let hours = parseInt(militaryTimeInput.split(":")[0]);
|
let hours = parseInt(militaryTimeInput.split(":")[0]);
|
||||||
const minutes = militaryTimeInput.split(":")[1];
|
const minutes = militaryTimeInput.split(":")[1];
|
||||||
let meridianNotation = hours > 11 ? "PM" : "AM";
|
const meridianNotation = hours > 11 ? "PM" : "AM";
|
||||||
if (hours > 12) {
|
if (hours > 12) {
|
||||||
hours -= 12;
|
hours -= 12;
|
||||||
}
|
}
|
||||||
|
|
@ -322,18 +346,11 @@ export default {
|
||||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
//TODO: replace properties with real values once they are available
|
|
||||||
await this.dispatchStoreAction(
|
await this.dispatchStoreAction(
|
||||||
this.storeActions.SAVE_SCHEDULE,
|
this.storeActions.SAVE_SCHEDULE,
|
||||||
{
|
this.appointmentDateAndTime,
|
||||||
date: "2023-07-04T00:00:00",
|
|
||||||
startTime: "2023-07-04T12:00:00",
|
|
||||||
endTime: "2023-07-04T17:00:00",
|
|
||||||
routeCode: "03341-01820-S-B*20232*11 AM",
|
|
||||||
},
|
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
|
navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
{{ formattedButtonLabelSubCopy }}
|
{{ formattedButtonLabelSubCopy }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span v-if="screenReaderOnlyText" class="sr-only">
|
<span v-if="screenReaderOnlyText" class="sr-only">
|
||||||
{{ screenReaderOnlyText }}
|
{{ screenReaderOnlyText }}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -28,7 +27,7 @@ import baseInputButton from "@/digital-components/base-input-button/base-input-b
|
||||||
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "timeslotModalListButton",
|
name: "timeSlotModalListButton",
|
||||||
mixins: [inputButtonWrapperMixin],
|
mixins: [inputButtonWrapperMixin],
|
||||||
computed: {
|
computed: {
|
||||||
formattedButtonLabelSubCopy() {
|
formattedButtonLabelSubCopy() {
|
||||||
|
|
@ -52,9 +51,6 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.loader {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.list-button {
|
.list-button {
|
||||||
outline: none;
|
outline: none;
|
||||||
input[type="radio"],
|
input[type="radio"],
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
typeStyle="small"
|
typeStyle="small"
|
||||||
class="duration-text-block" />
|
class="duration-text-block" />
|
||||||
<buttonQuestion
|
<buttonQuestion
|
||||||
buttonTypeString="timeslotModalListButton"
|
buttonTypeString="timeSlotModalListButton"
|
||||||
:buttonTypeObject="timeslotModalListButton"
|
:buttonTypeObject="timeSlotModalListButton"
|
||||||
:answers="availableTimeSlots"
|
:answers="availableTimeSlots"
|
||||||
groupName="ChooseTimeSlot"
|
groupName="ChooseTimeSlot"
|
||||||
textPosition="text-center"
|
textPosition="text-center"
|
||||||
|
|
@ -41,10 +41,9 @@
|
||||||
import modal from "@/digital-components/modal/modal";
|
import modal from "@/digital-components/modal/modal";
|
||||||
import textBlock from "@/digital-components/text-block/text-block";
|
import textBlock from "@/digital-components/text-block/text-block";
|
||||||
import buttonQuestion from "@/digital-components/button-question/button-question";
|
import buttonQuestion from "@/digital-components/button-question/button-question";
|
||||||
import timeslotModalListButton from "./timeslot-modal-list-button/timeslot-modal-list-button";
|
import timeSlotModalListButton from "./time-slot-modal-list-button/time-slot-modal-list-button";
|
||||||
|
|
||||||
// TODO: Move this somewhere more global
|
// TODO: Move this somewhere more global
|
||||||
import { DAYS_OF_WEEK, MONTHS_OF_YEAR } from "@/digital-components/date-picker/mixins/constants.js";
|
|
||||||
import { defineRule, useField } from "vee-validate";
|
import { defineRule, useField } from "vee-validate";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
import { required } from "@/helpers/validation-rules";
|
import { required } from "@/helpers/validation-rules";
|
||||||
|
|
@ -80,8 +79,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedTimeSlotId: null,
|
selectedTimeSlotId: null,
|
||||||
isSelectedAppointmentPremium: null,
|
timeSlotModalListButton: timeSlotModalListButton,
|
||||||
timeslotModalListButton: timeslotModalListButton,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
|
@ -96,7 +94,7 @@ export default {
|
||||||
// Run component validation that is used at parent level
|
// Run component validation that is used at parent level
|
||||||
this.handleChange(this.modelValue.id);
|
this.handleChange(this.modelValue.id);
|
||||||
},
|
},
|
||||||
dateAndTimeSlotData(newValue, oldValue) {
|
availableTimeSlots(newValue) {
|
||||||
this.autoSelectTimeSlotIfOnlyOneIsAvailable(newValue);
|
this.autoSelectTimeSlotIfOnlyOneIsAvailable(newValue);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -159,65 +157,30 @@ export default {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
dateSelectedReadableDate() {
|
dateSelectedReadableDate() {
|
||||||
if (this.dateAndTimeSlotData === null) {
|
if (!this.dateAndTimeSlotData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// This conversion ensures we don't get get GMT induced date changes
|
|
||||||
const dateObject = new Date(`${this.dateAndTimeSlotData.dateString}T00:00:00`);
|
|
||||||
const weekdayName = DAYS_OF_WEEK[dateObject.getDay()];
|
|
||||||
const month = MONTHS_OF_YEAR[dateObject.getMonth()];
|
|
||||||
const numberDayOfMonth = dateObject.getDate();
|
|
||||||
// Ex. Tuesday, April 23
|
|
||||||
return `${weekdayName}, ${month} ${numberDayOfMonth}`;
|
|
||||||
},
|
|
||||||
availableTimeSlots() {
|
|
||||||
if (this.dateAndTimeSlotData === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let availableTimeSlots;
|
|
||||||
if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
|
|
||||||
availableTimeSlots = [
|
|
||||||
{
|
|
||||||
value: this.dateAndTimeSlotData.timeSlots[0].id,
|
|
||||||
buttonLabel: this.dropoffButtonText,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
availableTimeSlots = this.dateAndTimeSlotData.timeSlots.map((timeslot) => {
|
|
||||||
let readableTime;
|
|
||||||
if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
|
|
||||||
readableTime = this.getDisplayTextForMilitaryTime(timeslot.startTime);
|
|
||||||
} else if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
|
|
||||||
readableTime = `${this.getDisplayTextForMilitaryTime(
|
|
||||||
timeslot.startTime
|
|
||||||
)} - ${this.getDisplayTextForMilitaryTime(timeslot.endTime)}`;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
value: timeslot.id,
|
|
||||||
buttonLabel: readableTime,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
|
// This conversion ensures we don't get get GMT induced date changes
|
||||||
const isPremiumTimeSlot = this.dateAndTimeSlotData.timeSlots[0].offerPremium;
|
const dateObject = new Date(`${this.dateAndTimeSlotData.dateString}T00:00:00`);
|
||||||
const hasPremiumPartAvailable =
|
// Ex: Tuesday, April 22
|
||||||
this.premiumAppointmentFee?.partType === PREMIUM_FEE_PART_TYPE;
|
return dateObject.toLocaleDateString("en-us", {
|
||||||
if (isPremiumTimeSlot && hasPremiumPartAvailable) {
|
weekday: "long",
|
||||||
const formattedPrice =
|
month: "long",
|
||||||
"+$" + this.getTotalLineItemPrice(this.premiumAppointmentFee).toFixed(2);
|
day: "numeric",
|
||||||
availableTimeSlots.unshift({
|
|
||||||
// Unique value is required for each <input> and the premium appoinment shares a timeslot ID
|
|
||||||
value: this.addPremiumFlagToInput(this.dateAndTimeSlotData.timeSlots[0].id),
|
|
||||||
buttonLabel: this.premiumAppointmentButtonText,
|
|
||||||
buttonLabelSubCopy: formattedPrice,
|
|
||||||
additionalButtonData: {
|
|
||||||
isPremiumAppointment: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
availableTimeSlots() {
|
||||||
|
if (!this.dateAndTimeSlotData) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
|
||||||
|
return this.getAvailableTimeSlotsForDropOff(this.dateAndTimeSlotData.timeSlots);
|
||||||
|
} else if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
|
||||||
|
return this.getAvailableTimeSlotsForMobile(this.dateAndTimeSlotData.timeSlots);
|
||||||
|
} else {
|
||||||
|
return this.getAvailableTimeSlotsForInshop(this.dateAndTimeSlotData.timeSlots);
|
||||||
}
|
}
|
||||||
return availableTimeSlots;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -226,34 +189,33 @@ export default {
|
||||||
},
|
},
|
||||||
// fires any time the footer button is used, is fired before "onModalClosed"
|
// fires any time the footer button is used, is fired before "onModalClosed"
|
||||||
closeModal() {
|
closeModal() {
|
||||||
if (this.selectedTimeSlotId.toString().includes(PREMIUM_TIME_SLOT_ID_FLAG)) {
|
let isSelectedAppointmentPremium = false;
|
||||||
|
if (this.selectedTimeSlotId.includes(PREMIUM_TIME_SLOT_ID_FLAG)) {
|
||||||
this.selectedTimeSlotId = this.removePremiumFlagFromInput(this.selectedTimeSlotId);
|
this.selectedTimeSlotId = this.removePremiumFlagFromInput(this.selectedTimeSlotId);
|
||||||
this.isSelectedAppointmentPremium = true;
|
isSelectedAppointmentPremium = true;
|
||||||
} else {
|
|
||||||
this.isSelectedAppointmentPremium = false;
|
|
||||||
}
|
}
|
||||||
const selectedTimeSlotData = {
|
const selectedTimeSlotData = {
|
||||||
id: this.selectedTimeSlotId,
|
id: this.selectedTimeSlotId,
|
||||||
isPremiumAppointment: this.isSelectedAppointmentPremium,
|
isPremiumAppointment: isSelectedAppointmentPremium,
|
||||||
};
|
};
|
||||||
this.$emit("update:modelValue", selectedTimeSlotData);
|
this.$emit("update:modelValue", selectedTimeSlotData);
|
||||||
this.$refs["timeSlots"].closeModal();
|
this.$refs["timeSlots"].closeModal();
|
||||||
},
|
},
|
||||||
// fires any time the modal is closed, AFTER "closeModal" fires if footer button is used
|
// fires any time the modal is closed, AFTER "closeModal" fires if footer button is used
|
||||||
onModalClosed() {
|
onModalClosed() {
|
||||||
this.isSelectedAppointmentPremium = this.modelValue.isPremiumAppointment;
|
// Reset component state to parent's state
|
||||||
if (this.isSelectedAppointmentPremium) {
|
if (this.modelValue.isPremiumAppointment) {
|
||||||
this.selectedTimeSlotId = this.addPremiumFlagToInput(this.modelValue.id);
|
this.selectedTimeSlotId = this.addPremiumFlagToInput(this.modelValue.id);
|
||||||
} else {
|
} else {
|
||||||
this.selectedTimeSlotId = this.modelValue.id;
|
this.selectedTimeSlotId = this.modelValue.id;
|
||||||
}
|
}
|
||||||
this.$emit("time-slot-modal-closed");
|
this.$emit("time-slot-modal-closed");
|
||||||
},
|
},
|
||||||
// Expected input: "HH:MM:SS"
|
// Expected input: "HH:MM"
|
||||||
getDisplayTextForMilitaryTime(militaryTimeInput) {
|
getDisplayTextForMilitaryTime(militaryTimeInput) {
|
||||||
let hours = parseInt(militaryTimeInput.split(":")[0]);
|
let hours = parseInt(militaryTimeInput.split(":")[0]);
|
||||||
const minutes = militaryTimeInput.split(":")[1];
|
const minutes = militaryTimeInput.split(":")[1];
|
||||||
let meridianNotation = hours > 11 ? "PM" : "AM";
|
const meridianNotation = hours > 11 ? "PM" : "AM";
|
||||||
if (hours > 12) {
|
if (hours > 12) {
|
||||||
hours -= 12;
|
hours -= 12;
|
||||||
}
|
}
|
||||||
|
|
@ -270,24 +232,69 @@ export default {
|
||||||
}
|
}
|
||||||
return displayTextForDurationLength;
|
return displayTextForDurationLength;
|
||||||
},
|
},
|
||||||
autoSelectTimeSlotIfOnlyOneIsAvailable(newdateAndTimeSlotDataValue) {
|
getAvailableTimeSlotsForInshop(timeSlotsForSelectedDate) {
|
||||||
const numberOfOptions = newdateAndTimeSlotDataValue?.timeSlots.length;
|
return timeSlotsForSelectedDate.map((timeSlot) => {
|
||||||
if (
|
const readableTime = this.getDisplayTextForMilitaryTime(timeSlot.startTime);
|
||||||
numberOfOptions === 1 &&
|
return {
|
||||||
!(
|
value: timeSlot.id,
|
||||||
this.appointmentType === AppointmentTypeStrings.MOBILE &&
|
buttonLabel: readableTime,
|
||||||
this.premiumAppointmentFee &&
|
};
|
||||||
newdateAndTimeSlotDataValue.timeSlots[0].offerPremium
|
});
|
||||||
)
|
},
|
||||||
) {
|
getAvailableTimeSlotsForDropOff(timeSlotsForSelectedDate) {
|
||||||
this.selectedTimeSlotId = newdateAndTimeSlotDataValue.timeSlots[0].id;
|
return [
|
||||||
|
{
|
||||||
|
value: timeSlotsForSelectedDate[0].id,
|
||||||
|
buttonLabel: this.dropoffButtonText,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
getAvailableTimeSlotsForMobile(timeSlotsForSelectedDate) {
|
||||||
|
const availableTimeSlots = timeSlotsForSelectedDate.map((timeSlot) => {
|
||||||
|
const readableTime = `${this.getDisplayTextForMilitaryTime(
|
||||||
|
timeSlot.startTime
|
||||||
|
)} - ${this.getDisplayTextForMilitaryTime(timeSlot.endTime)}`;
|
||||||
|
return {
|
||||||
|
value: timeSlot.id,
|
||||||
|
buttonLabel: readableTime,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const isPremiumTimeSlot = timeSlotsForSelectedDate[0].offerPremium;
|
||||||
|
const hasPremiumPartAvailable =
|
||||||
|
this.premiumAppointmentFee?.partType === PREMIUM_FEE_PART_TYPE;
|
||||||
|
if (isPremiumTimeSlot && hasPremiumPartAvailable) {
|
||||||
|
availableTimeSlots.unshift(
|
||||||
|
this.getPremiumAppointmentTimeSlot(timeSlotsForSelectedDate[0])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableTimeSlots;
|
||||||
|
},
|
||||||
|
getPremiumAppointmentTimeSlot(timeSlotData) {
|
||||||
|
const formattedPrice =
|
||||||
|
"+$" + this.getTotalLineItemPrice(this.premiumAppointmentFee).toFixed(2);
|
||||||
|
return {
|
||||||
|
// Unique value is required for each <input> and the premium appoinment shares a timeSlot ID
|
||||||
|
value: this.addPremiumFlagToInput(timeSlotData.id),
|
||||||
|
buttonLabel: this.premiumAppointmentButtonText,
|
||||||
|
buttonLabelSubCopy: formattedPrice,
|
||||||
|
additionalButtonData: {
|
||||||
|
isPremiumAppointment: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
autoSelectTimeSlotIfOnlyOneIsAvailable(newAvailableTimeSlotsValue) {
|
||||||
|
const numberOfOptions = newAvailableTimeSlotsValue?.length;
|
||||||
|
if (numberOfOptions === 1) {
|
||||||
|
this.selectedTimeSlotId = newAvailableTimeSlotsValue[0].value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addPremiumFlagToInput(timeSlotId) {
|
addPremiumFlagToInput(timeSlotId) {
|
||||||
return (timeSlotId += PREMIUM_TIME_SLOT_ID_FLAG);
|
return (timeSlotId += PREMIUM_TIME_SLOT_ID_FLAG);
|
||||||
},
|
},
|
||||||
removePremiumFlagFromInput(timeSlotId) {
|
removePremiumFlagFromInput(timeSlotId) {
|
||||||
return parseInt(timeSlotId.trim(PREMIUM_TIME_SLOT_ID_FLAG.length));
|
return timeSlotId.substring(0, timeSlotId.length - PREMIUM_TIME_SLOT_ID_FLAG.length);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
import store from "@/store";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
|
||||||
export async function getPricedMobileFeePart(serviceZipCode) {
|
export async function getPricedMobileFeePart(serviceZipCode) {
|
||||||
|
|
@ -42,3 +43,48 @@ export async function getServiceabilityDetails(serviceZipCode, lineItems) {
|
||||||
|
|
||||||
return Promise.resolve(serviceabilityDetails);
|
return Promise.resolve(serviceabilityDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAvailabilityRating(
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
shopAppointmentType,
|
||||||
|
providerNumber
|
||||||
|
) {
|
||||||
|
// For a given shop provider number and date range, get the appointment time slots available
|
||||||
|
const shopTimeSlots = await baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.GET_SHOP_TIME_SLOTS,
|
||||||
|
{
|
||||||
|
providerNumber: providerNumber,
|
||||||
|
startDate: startDate,
|
||||||
|
endDate: endDate,
|
||||||
|
shopAppointmentType: shopAppointmentType,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Rate the availability for the shop
|
||||||
|
let numberOfAppointmentsPerDay = [];
|
||||||
|
for (let i = 0; i < shopTimeSlots.data.days.length; i++) {
|
||||||
|
numberOfAppointmentsPerDay.push(shopTimeSlots.data.days[i].timeSlots.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateRange = 7;
|
||||||
|
const minimumNumberOfAppointmentsPerDay = 1;
|
||||||
|
const numberOfDaysToEvaluate = 2;
|
||||||
|
|
||||||
|
let daysWithMinimalAppointmentsCount = 0;
|
||||||
|
for (let i = 0; i < dateRange; i++) {
|
||||||
|
if (numberOfAppointmentsPerDay[i] >= minimumNumberOfAppointmentsPerDay) {
|
||||||
|
daysWithMinimalAppointmentsCount++;
|
||||||
|
if (daysWithMinimalAppointmentsCount >= numberOfDaysToEvaluate) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isGoodAvailability = daysWithMinimalAppointmentsCount >= numberOfDaysToEvaluate;
|
||||||
|
|
||||||
|
const shopStatus = isGoodAvailability ? "high" : "low";
|
||||||
|
|
||||||
|
return Promise.resolve(shopStatus);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,186 @@
|
||||||
import { getPricedMobileFeePart, getServiceabilityDetails } from "./service-location-helper";
|
import {
|
||||||
|
getPricedMobileFeePart,
|
||||||
|
getServiceabilityDetails,
|
||||||
|
getAvailabilityRating,
|
||||||
|
} from "./service-location-helper";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
|
|
||||||
|
jest.mock("@/store", () => ({
|
||||||
|
getters: {
|
||||||
|
order: {
|
||||||
|
vehicle: {
|
||||||
|
year: null,
|
||||||
|
make: null,
|
||||||
|
model: null,
|
||||||
|
style: null,
|
||||||
|
carId: null,
|
||||||
|
category: null,
|
||||||
|
vin: null,
|
||||||
|
imageUrl: null,
|
||||||
|
imageVifNumber: null,
|
||||||
|
imageColor: null,
|
||||||
|
registration: {
|
||||||
|
licensePlate: null,
|
||||||
|
address: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
zipCode: null,
|
||||||
|
firstName: null,
|
||||||
|
lastName: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
address: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
zipCode: null,
|
||||||
|
zipCodeCtu: null,
|
||||||
|
appointmentType: null,
|
||||||
|
provider: {
|
||||||
|
providerNumber: null,
|
||||||
|
address: {
|
||||||
|
streetAddress: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
zip: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
customer: {
|
||||||
|
emailAddress: null,
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: null,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: null,
|
||||||
|
partQuestionAnswers: null,
|
||||||
|
moldingQuestionAnswers: null,
|
||||||
|
capabilityQuestionAnswers: null,
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: null,
|
||||||
|
supportingItems: null,
|
||||||
|
vaps: null,
|
||||||
|
serverData: null,
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: null,
|
||||||
|
insuranceCoverage: {
|
||||||
|
isVerified: null,
|
||||||
|
coverageStatus: null,
|
||||||
|
},
|
||||||
|
parentAccountNumber: 0,
|
||||||
|
},
|
||||||
|
schedule: {
|
||||||
|
date: null,
|
||||||
|
startTime: null,
|
||||||
|
endTime: null,
|
||||||
|
routeCode: null,
|
||||||
|
},
|
||||||
|
referralNumber: null,
|
||||||
|
referralDate: null,
|
||||||
|
referralCorrelationId: null,
|
||||||
|
eon: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
const mockStoreActionGetMobileFeePart = storeActions.GET_MOBILE_FEE_PART;
|
const mockStoreActionGetMobileFeePart = storeActions.GET_MOBILE_FEE_PART;
|
||||||
const mockStoreActionPriceOrderItemsAndSaveServerData =
|
const mockStoreActionPriceOrderItemsAndSaveServerData =
|
||||||
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA;
|
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA;
|
||||||
const mockStoreActionGetServiceabilityDetails = storeActions.GET_SERVICEABILITY_DETAILS;
|
const mockStoreActionGetServiceabilityDetails = storeActions.GET_SERVICEABILITY_DETAILS;
|
||||||
|
const mockStoreActionGetShopTimeSlots = storeActions.GET_SHOP_TIME_SLOTS;
|
||||||
|
|
||||||
|
const mockGetShopTimeSlotsGoodAvailability = {
|
||||||
|
estimatedServiceMinutesMinimum: 0,
|
||||||
|
estimatedServiceMinutesMaximimum: 0,
|
||||||
|
days: [
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: "string",
|
||||||
|
startTime: "",
|
||||||
|
endTime: "",
|
||||||
|
offerPremium: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: "string",
|
||||||
|
startTime: "",
|
||||||
|
endTime: "",
|
||||||
|
offerPremium: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockGetShopTimeSlotsLowAvailability = {
|
||||||
|
estimatedServiceMinutesMinimum: 0,
|
||||||
|
estimatedServiceMinutesMaximimum: 0,
|
||||||
|
days: [
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "string",
|
||||||
|
timeSlots: [
|
||||||
|
{
|
||||||
|
id: "string",
|
||||||
|
startTime: "",
|
||||||
|
endTime: "",
|
||||||
|
offerPremium: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
jest.mock("@/mixins/base-mixin.js", () => ({
|
jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -18,7 +194,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
dispatchStoreAction: jest.fn().mockImplementation((actionName) => {
|
dispatchStoreAction: jest.fn().mockImplementation((actionName, request) => {
|
||||||
if (actionName === mockStoreActionGetMobileFeePart) {
|
if (actionName === mockStoreActionGetMobileFeePart) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -50,6 +226,14 @@ jest.mock("@/mixins/base-mixin.js", () => ({
|
||||||
isRecalibrationServiceableMobile: true,
|
isRecalibrationServiceableMobile: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (actionName === mockStoreActionGetShopTimeSlots) {
|
||||||
|
if (request.providerNumber == "0000001") {
|
||||||
|
return Promise.resolve(mockGetShopTimeSlotsGoodAvailability);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(mockGetShopTimeSlotsLowAvailability);
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
@ -124,4 +308,25 @@ describe("service-location-helper.js", () => {
|
||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getAvailabilityRating", () => {
|
||||||
|
// it("Should return a 'Good' rating", async () => {
|
||||||
|
// // Arrange
|
||||||
|
// const providerNumber = "0000001";
|
||||||
|
// const expected = "Good";
|
||||||
|
// // Act
|
||||||
|
// const result = await getAvailabilityRating(providerNumber);
|
||||||
|
// // Assert
|
||||||
|
// expect(result).toEqual(expected);
|
||||||
|
// });
|
||||||
|
// it("Should return a 'Low' rating", async () => {
|
||||||
|
// // Arrange
|
||||||
|
// const providerNumber = "0000000";
|
||||||
|
// const expected = "Low";
|
||||||
|
// // Act
|
||||||
|
// const result = await getAvailabilityRating(providerNumber);
|
||||||
|
// // Assert
|
||||||
|
// expect(result).toEqual(expected);
|
||||||
|
// });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ export default {
|
||||||
this.internalModel = deepClone(this.modelValue);
|
this.internalModel = deepClone(this.modelValue);
|
||||||
},
|
},
|
||||||
onModalClosed() {
|
onModalClosed() {
|
||||||
|
this.displayInvalidZipAlert = false;
|
||||||
this.internalModel = deepClone(this.modelValue);
|
this.internalModel = deepClone(this.modelValue);
|
||||||
this.resetValidation();
|
this.resetValidation();
|
||||||
},
|
},
|
||||||
|
|
@ -261,15 +262,19 @@ export default {
|
||||||
this.$emit("updated-serviceability", serviceabilityDetails.data);
|
this.$emit("updated-serviceability", serviceabilityDetails.data);
|
||||||
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
|
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
|
||||||
|
|
||||||
// Update the page level model
|
|
||||||
this.$emit("update:modelValue", this.internalModel);
|
|
||||||
|
|
||||||
if (this.onZipUpdateCallback) {
|
if (this.onZipUpdateCallback) {
|
||||||
await this.onZipUpdateCallback(serviceZipCode);
|
await this.onZipUpdateCallback(serviceZipCode);
|
||||||
}
|
}
|
||||||
|
// Update the page level model
|
||||||
|
this.$emit("update:modelValue", this.internalModel);
|
||||||
|
|
||||||
this.closeModal();
|
this.closeModal();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Update the page level model
|
||||||
|
this.$emit("update:modelValue", this.internalModel);
|
||||||
|
|
||||||
|
this.closeModal();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { mount } from "@vue/test-utils";
|
||||||
import shopListButton from "./shop-list-button";
|
import shopListButton from "./shop-list-button";
|
||||||
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
describe("service-package-radio.vue", () => {
|
describe("shop-list-button.vue", () => {
|
||||||
it("Should include buttonLabel in html", async () => {
|
it("Should include buttonLabel in html", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
let { wrapper } = setupMocks({
|
let { wrapper } = setupMocks({
|
||||||
|
|
@ -49,6 +49,18 @@ describe("service-package-radio.vue", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const startDate = new Date();
|
||||||
|
const endDate = new Date();
|
||||||
|
endDate.setDate(startDate.getDate() + 7);
|
||||||
|
const getAvailabilityRating = jest.fn().mockImplementation((actionName, request) => {
|
||||||
|
return Promise.resolve({
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const formattedStartDate = startDate.toISOString().split("T")[0];
|
||||||
|
const formattedEndDate = endDate.toISOString().split("T")[0];
|
||||||
|
|
||||||
const mockProps = {
|
const mockProps = {
|
||||||
buttonLabel: "buttonLabel test copy",
|
buttonLabel: "buttonLabel test copy",
|
||||||
buttonLabelSubCopy: "buttonLabelSubCopy test copy",
|
buttonLabelSubCopy: "buttonLabelSubCopy test copy",
|
||||||
|
|
@ -58,6 +70,12 @@ const mockProps = {
|
||||||
value: 0,
|
value: 0,
|
||||||
modelValue: 0,
|
modelValue: 0,
|
||||||
groupName: "mockGroup",
|
groupName: "mockGroup",
|
||||||
|
additionalButtonData: {
|
||||||
|
availabilityRatingCallback: getAvailabilityRating,
|
||||||
|
startDate: formattedStartDate,
|
||||||
|
endDate: formattedEndDate,
|
||||||
|
shopAppointmentType: "Dropoff",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function setupMocks({ mountOptionsMockData = {} }) {
|
function setupMocks({ mountOptionsMockData = {} }) {
|
||||||
|
|
|
||||||
|
|
@ -11,26 +11,32 @@
|
||||||
<span class="m-0 button-label-copy" :class="textPosition">{{
|
<span class="m-0 button-label-copy" :class="textPosition">{{
|
||||||
buttonLabel
|
buttonLabel
|
||||||
}}</span>
|
}}</span>
|
||||||
<span class="m-0 button-label-sub-copy" :class="textPosition">{{
|
<span class="m-0 caption ms-1" :class="textPosition">{{
|
||||||
buttonLabelSubCopy
|
buttonLabelSubCopy
|
||||||
}}</span>
|
}}</span>
|
||||||
<div
|
<div
|
||||||
class="availability-indicator"
|
v-if="displayAvailabilityIndicators"
|
||||||
:class="availability === 'high' ? 'green' : 'red'">
|
class="availability-indicator rounded-pill"
|
||||||
<span class="m-0 button-auxillary-copy">{{ buttonAuxillaryCopy }}</span>
|
:class="availabilityRatingClass">
|
||||||
|
<div
|
||||||
|
v-if="!isLoaderDisplayed"
|
||||||
|
class="availability-badge"
|
||||||
|
:class="availabilityRating == 'high' ? 'green' : 'red'"></div>
|
||||||
|
<span v-if="!isLoaderDisplayed" class="m-0 button-auxillary-copy">{{
|
||||||
|
badgeText
|
||||||
|
}}</span>
|
||||||
|
<loader v-if="isLoaderDisplayed" :class="['left', 'no-block']" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row-two">
|
||||||
<span
|
<span
|
||||||
v-if="buttonBodyCopy"
|
v-if="buttonBodyCopy"
|
||||||
class="m-0 button-label-sub-copy small"
|
class="m-0 button-label-sub-copy small"
|
||||||
:class="textPosition"
|
|
||||||
v-html="buttonBodyCopy"></span>
|
v-html="buttonBodyCopy"></span>
|
||||||
|
</div>
|
||||||
<span v-if="screenReaderOnlyText" class="sr-only">
|
<span v-if="screenReaderOnlyText" class="sr-only">
|
||||||
{{ screenReaderOnlyText }}
|
{{ screenReaderOnlyText }}
|
||||||
</span>
|
</span>
|
||||||
<loader
|
|
||||||
v-if="isLoaderDisplayed && selectingInitiatesLoad"
|
|
||||||
:class="[this.loaderColor, this.loaderPosition]" />
|
|
||||||
</div>
|
</div>
|
||||||
</baseInputButton>
|
</baseInputButton>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
@ -40,32 +46,59 @@
|
||||||
import loader from "@/ux-components/loader/loader";
|
import loader from "@/ux-components/loader/loader";
|
||||||
import baseInputButton from "@/digital-components/base-input-button/base-input-button";
|
import baseInputButton from "@/digital-components/base-input-button/base-input-button";
|
||||||
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
import experimentMixin from "@/mixins/experiment-mixin";
|
||||||
|
import { experimentSettings } from "@/constants/experiments";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "shopListButton",
|
name: "shopListButton",
|
||||||
mixins: [inputButtonWrapperMixin],
|
mixins: [inputButtonWrapperMixin],
|
||||||
props: {
|
beforeMount() {
|
||||||
loaderColor: String,
|
if (this.displayAvailabilityIndicators) {
|
||||||
loaderPosition: {
|
this.displayLoader();
|
||||||
type: String,
|
const startDate = this.additionalButtonData.startDate;
|
||||||
default: "right",
|
const endDate = this.additionalButtonData.endDate;
|
||||||
},
|
const shopAppointmentType = this.additionalButtonData.shopAppointmentType;
|
||||||
|
|
||||||
|
this.additionalButtonData
|
||||||
|
.availabilityRatingCallback(startDate, endDate, shopAppointmentType, this.value)
|
||||||
|
.then((data) => {
|
||||||
|
this.availabilityRating = data;
|
||||||
|
this.isLoaderDisplayed = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoaderDisplayed: false,
|
isLoaderDisplayed: false,
|
||||||
availability: "low",
|
availabilityRating: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
displayAvailabilityIndicators() {
|
||||||
|
return experimentMixin.methods.hasSettingEqualTo(
|
||||||
|
experimentSettings.DISPLAY_AVAILABILITY_INDICATORS,
|
||||||
|
"true"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
availabilityRatingClass() {
|
||||||
|
if (this.availabilityRating == null) {
|
||||||
|
return "gray";
|
||||||
|
} else {
|
||||||
|
return this.availabilityRating == "high" ? "green" : "red";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
badgeText() {
|
||||||
|
if (this.availabilityRating != null) {
|
||||||
|
return this.availabilityRating == "high" ? "Appts available" : "Appts low";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayLoader() {
|
displayLoader() {
|
||||||
this.isLoaderDisplayed = true;
|
this.isLoaderDisplayed = true;
|
||||||
},
|
},
|
||||||
preHandleAnswerChange() {
|
|
||||||
if (this.selectingInitiatesLoad) {
|
|
||||||
this.displayLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
loader,
|
loader,
|
||||||
|
|
@ -75,9 +108,6 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.loader {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.list-button {
|
.list-button {
|
||||||
outline: none;
|
outline: none;
|
||||||
input[type="radio"],
|
input[type="radio"],
|
||||||
|
|
@ -103,10 +133,6 @@ export default {
|
||||||
&:checked + .list-button-content span {
|
&:checked + .list-button-content span {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
&:checked + .list-button-content span:nth-child(2) {
|
|
||||||
font-weight: 400;
|
|
||||||
color: $gray-600;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.list-button-content {
|
.list-button-content {
|
||||||
|
|
@ -127,53 +153,83 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.button-content {
|
.button-content {
|
||||||
|
row-gap: 0.25rem;
|
||||||
|
|
||||||
.row-one {
|
.row-one {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 0.25rem !important;
|
line-height: 1.5rem;
|
||||||
|
|
||||||
.button-label-copy {
|
.button-label-copy {
|
||||||
flex-grow: 0;
|
|
||||||
line-height: 1.5rem;
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-label-sub-copy {
|
.availability-indicator {
|
||||||
flex-grow: 1;
|
background-repeat: no-repeat;
|
||||||
line-height: 1.25rem !important;
|
display: flex;
|
||||||
font-weight: 400;
|
align-items: center;
|
||||||
font-size: 0.75rem;
|
margin-left: auto;
|
||||||
color: #727676;
|
padding: 0.125rem 0.5rem;
|
||||||
padding-left: 0.25rem;
|
|
||||||
|
.availability-badge {
|
||||||
|
display: inline;
|
||||||
|
width: 13px;
|
||||||
|
height: 12px;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin: 0 0.25rem 0 0;
|
||||||
|
|
||||||
|
&.green {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 13 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.5 12C3.19159 12 0.5 9.30841 0.5 6C0.5 2.69159 3.19159 0 6.5 0C9.80841 0 12.5 2.69159 12.5 6C12.5 9.30841 9.80841 12 6.5 12ZM6.5 0.785047C3.62449 0.785047 1.28505 3.12449 1.28505 6C1.28505 8.87551 3.62449 11.215 6.5 11.215C9.37551 11.215 11.715 8.87551 11.715 6C11.715 3.12449 9.37551 0.785047 6.5 0.785047Z' fill='%23006A36'/%3E%3Cpath d='M5.697 7.95252C5.5927 7.95252 5.49289 7.91102 5.41999 7.837L3.90597 6.32299C3.75233 6.16934 3.75233 5.92149 3.90597 5.76785C4.05962 5.6142 4.30747 5.6142 4.46111 5.76785L5.69812 7.00373L8.53999 4.16186C8.69364 4.00822 8.94149 4.00822 9.09513 4.16186C9.24878 4.31551 9.24878 4.56336 9.09513 4.717L5.97626 7.83588C5.90224 7.9099 5.80242 7.9514 5.69925 7.9514L5.697 7.95252Z' fill='%23006A36'/%3E%3C/svg%3E%0A");
|
||||||
}
|
}
|
||||||
|
|
||||||
.availability-indicator {
|
&.red {
|
||||||
display: none;
|
background-image: url("data:image/svg+xml,%3Csvg width='13' height='12' viewBox='0 0 13 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.5 12C3.19159 12 0.5 9.30841 0.5 6C0.5 2.69159 3.19159 0 6.5 0C9.80841 0 12.5 2.69159 12.5 6C12.5 9.30841 9.80841 12 6.5 12ZM6.5 0.785047C3.62449 0.785047 1.28505 3.12449 1.28505 6C1.28505 8.87551 3.62449 11.215 6.5 11.215C9.37551 11.215 11.715 8.87551 11.715 6C11.715 3.12449 9.37551 0.785047 6.5 0.785047Z' fill='%23006A36'/%3E%3Csvg width='13' height='12' viewBox='0 0 13 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.5 0C9.81368 0 12.5 2.68632 12.5 6C12.5 9.31368 9.81368 12 6.5 12C3.18632 12 0.5 9.31368 0.5 6C0.5 2.68632 3.18632 0 6.5 0ZM6.5 0.84C3.6548 0.84 1.34 3.1548 1.34 6C1.34 8.8452 3.6548 11.16 6.5 11.16C9.3452 11.16 11.66 8.8452 11.66 6C11.66 3.1548 9.3452 0.84 6.5 0.84ZM7.90018 4.00596C8.06422 3.84204 8.33002 3.84192 8.49406 4.00596C8.6581 4.17 8.6581 4.43592 8.49406 4.59996L7.0939 6L8.49406 7.40004C8.6581 7.56408 8.6581 7.83 8.49406 7.99404C8.4121 8.076 8.30458 8.11704 8.19706 8.11704C8.08966 8.11704 7.98214 8.076 7.90018 7.99404L6.50002 6.594L5.09986 7.99404C5.01778 8.076 4.91038 8.11704 4.80286 8.11704C4.69546 8.11704 4.58794 8.076 4.50598 7.99404C4.34182 7.83 4.34182 7.56408 4.50598 7.40004L5.90614 6L4.50598 4.59996C4.34182 4.43592 4.34182 4.17 4.50598 4.00596C4.66978 3.84192 4.93582 3.84204 5.09986 4.00596L6.50002 5.406L7.90018 4.00596Z' fill='%23AC160B'/%3E%3C/svg%3E%3C/svg%3E%0A");
|
||||||
flex-direction: row;
|
}
|
||||||
justify-content: center;
|
}
|
||||||
align-items: center;
|
|
||||||
padding: 0.125rem 1.5rem;
|
|
||||||
gap: 0.25rem;
|
|
||||||
background: #e3f2ea;
|
|
||||||
border-radius: 4.5rem;
|
|
||||||
|
|
||||||
.button-auxillary-copy {
|
.button-auxillary-copy {
|
||||||
|
box-sizing: border-box;
|
||||||
justify-content: right;
|
justify-content: right;
|
||||||
line-height: 1.25rem !important;
|
line-height: 1.25rem !important;
|
||||||
font-weight: 400;
|
font-weight: 500;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.green {
|
.loader {
|
||||||
color: #006a36;
|
padding: 0 0.25rem 0 0.25rem;
|
||||||
background: #e3f2ea;
|
padding-top: 0.125rem;
|
||||||
|
padding-bottom: 0.125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.red {
|
.loader:after {
|
||||||
color: #ac160b;
|
background-color: $gray-300 !important;
|
||||||
background: #e3f2ea;
|
height: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.green {
|
||||||
|
color: $green-700;
|
||||||
|
background-color: $green-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.red {
|
||||||
|
color: $red-600;
|
||||||
|
background-color: $red-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.gray {
|
||||||
|
color: $gray-600 !important;
|
||||||
|
background-color: $gray-100;
|
||||||
|
padding-left: 0.125rem;
|
||||||
|
padding-right: 0.125rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.row-two {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@
|
||||||
textPosition="text-start"
|
textPosition="text-start"
|
||||||
v-model="selectedProviderNumber"
|
v-model="selectedProviderNumber"
|
||||||
isRequired
|
isRequired
|
||||||
validationRules="option-required" />
|
validationRules="option-required"
|
||||||
|
:additionalButtonData="additionalButtonData" />
|
||||||
<textLink
|
<textLink
|
||||||
v-show="displaySeeMoreLocationsLink"
|
v-show="displaySeeMoreLocationsLink"
|
||||||
ref="showMoreShopsLink"
|
ref="showMoreShopsLink"
|
||||||
|
|
@ -51,6 +52,8 @@ import { errorMessages } from "@/constants/error-messages";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
|
|
||||||
|
import { getAvailabilityRating } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
|
||||||
|
|
||||||
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -102,6 +105,21 @@ export default {
|
||||||
showMoreShopsLinkText() {
|
showMoreShopsLinkText() {
|
||||||
return this.getCmsContent("ShowMoreShopsLinkWidget", "Text");
|
return this.getCmsContent("ShowMoreShopsLinkWidget", "Text");
|
||||||
},
|
},
|
||||||
|
additionalButtonData() {
|
||||||
|
const startDate = new Date();
|
||||||
|
const endDate = new Date();
|
||||||
|
endDate.setDate(startDate.getDate() + 7);
|
||||||
|
|
||||||
|
const formattedStartDate = startDate.toISOString().split("T")[0];
|
||||||
|
const formattedEndDate = endDate.toISOString().split("T")[0];
|
||||||
|
|
||||||
|
return {
|
||||||
|
availabilityRatingCallback: getAvailabilityRating,
|
||||||
|
startDate: formattedStartDate,
|
||||||
|
endDate: formattedEndDate,
|
||||||
|
shopAppointmentType: this.selectedAppointmentType,
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loadInitialData(serviceZipCode) {
|
loadInitialData(serviceZipCode) {
|
||||||
|
|
@ -158,7 +176,7 @@ export default {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
if (this.shopIndex == this.shopProviders.length) {
|
if (this.shopIndex == this.shopProviders.length) {
|
||||||
this.displaySeeMoreLocationsLink = false;
|
this.displaySeeMoreLocationsLink = false;
|
||||||
|
|
@ -166,7 +184,7 @@ export default {
|
||||||
this.displaySeeMoreLocationsLink = true;
|
this.displaySeeMoreLocationsLink = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
this.scrollToPageBottom();
|
this.scrollToPageBottom();
|
||||||
},
|
},
|
||||||
|
|
@ -203,22 +221,20 @@ export default {
|
||||||
async handler(newValue) {
|
async handler(newValue) {
|
||||||
this.resetAnswers();
|
this.resetAnswers();
|
||||||
|
|
||||||
await this.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
this.selectedProviderNumber = null;
|
this.selectedProviderNumber = null;
|
||||||
|
|
||||||
this.$refs.buttonQuestion?.resetField();
|
await nextTick();
|
||||||
|
|
||||||
await this.$nextTick();
|
|
||||||
|
|
||||||
if (newValue !== "Mobile") {
|
if (newValue !== "Mobile") {
|
||||||
await this.getNextShopsFromList();
|
this.getNextShopsFromList();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shopProviders: {
|
shopProviders: {
|
||||||
async handler(newValue) {
|
async handler(newValue) {
|
||||||
await this.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
if (this.selectedAppointmentType) {
|
if (this.selectedAppointmentType) {
|
||||||
const selectedShopIndex = this.getSelectedProviderIndex(
|
const selectedShopIndex = this.getSelectedProviderIndex(
|
||||||
|
|
@ -230,7 +246,7 @@ export default {
|
||||||
await this.getNextShopsFromList(selectedShopIndex + 1);
|
await this.getNextShopsFromList(selectedShopIndex + 1);
|
||||||
} else {
|
} else {
|
||||||
await this.getNextShopsFromList();
|
await this.getNextShopsFromList();
|
||||||
await this.$nextTick();
|
await nextTick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -261,14 +277,16 @@ export default {
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 0.75rem;
|
background-size: 0.75rem;
|
||||||
background-position: 0.5rem 0.75rem;
|
background-position: 0.5rem 0.75rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 0.5rem 0.5rem 0.5rem 1.5rem !important;
|
||||||
|
gap: 0.25rem;
|
||||||
|
|
||||||
.alert-heading {
|
.alert-heading {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
}
|
}
|
||||||
p {
|
|
||||||
padding-left: 0.5rem;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -551,6 +551,7 @@ export const actions = {
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
lookupVehicleByYmms(context, { year, make, model, style }) {
|
lookupVehicleByYmms(context, { year, make, model, style }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LookupVehicleByYmms.method,
|
method: endpoints.LookupVehicleByYmms.method,
|
||||||
|
|
@ -558,6 +559,7 @@ export const actions = {
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
lookupVehicleByVin(context, { vin }) {
|
lookupVehicleByVin(context, { vin }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LookupVehicleByVin.method,
|
method: endpoints.LookupVehicleByVin.method,
|
||||||
|
|
@ -567,6 +569,7 @@ export const actions = {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
lookupVinByPlate(context, { licensePlate, licenseState }) {
|
lookupVinByPlate(context, { licensePlate, licenseState }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LookupVinByPlate.method,
|
method: endpoints.LookupVinByPlate.method,
|
||||||
|
|
@ -577,6 +580,7 @@ export const actions = {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
lookupVinByAddress(
|
lookupVinByAddress(
|
||||||
context,
|
context,
|
||||||
{ licenseLastName, licenseStreetAddress, licenseZip, licenseState }
|
{ licenseLastName, licenseStreetAddress, licenseZip, licenseState }
|
||||||
|
|
@ -592,6 +596,7 @@ export const actions = {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
lookupVinByImage(context, image) {
|
lookupVinByImage(context, image) {
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.append("vinImage", image);
|
data.append("vinImage", image);
|
||||||
|
|
@ -602,6 +607,7 @@ export const actions = {
|
||||||
isFormData: true,
|
isFormData: true,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
isVinByAddressPermissible(context, zip) {
|
isVinByAddressPermissible(context, zip) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.IsVinByAddressPermissible.method,
|
method: endpoints.IsVinByAddressPermissible.method,
|
||||||
|
|
@ -609,6 +615,7 @@ export const actions = {
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getVehicleMakes(context, { year }) {
|
getVehicleMakes(context, { year }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetVehicleMakes.method,
|
method: endpoints.GetVehicleMakes.method,
|
||||||
|
|
@ -616,6 +623,7 @@ export const actions = {
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getVehicleModels(context, { year, make }) {
|
getVehicleModels(context, { year, make }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetVehicleModels.method,
|
method: endpoints.GetVehicleModels.method,
|
||||||
|
|
@ -623,6 +631,7 @@ export const actions = {
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getVehicleStyles(context, { year, make, model }) {
|
getVehicleStyles(context, { year, make, model }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetVehicleStyles.method,
|
method: endpoints.GetVehicleStyles.method,
|
||||||
|
|
@ -630,6 +639,7 @@ export const actions = {
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setVehicle(context, { year, make, model, style }) {
|
setVehicle(context, { year, make, model, style }) {
|
||||||
return globalMethods
|
return globalMethods
|
||||||
.callHttpClient({
|
.callHttpClient({
|
||||||
|
|
@ -652,6 +662,7 @@ export const actions = {
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getDamageOptions(context, { carId }) {
|
getDamageOptions(context, { carId }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
methods: endpoints.GetDamageOptions.method,
|
methods: endpoints.GetDamageOptions.method,
|
||||||
|
|
@ -659,6 +670,7 @@ export const actions = {
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
validateZip(context, { zip }) {
|
validateZip(context, { zip }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
methods: endpoints.ValidateZip.method,
|
methods: endpoints.ValidateZip.method,
|
||||||
|
|
@ -673,18 +685,22 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
|
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
|
||||||
context.commit(storeMutations.UPDATE_VAPS, null);
|
context.commit(storeMutations.UPDATE_VAPS, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetRegistrationAndDependencies(context) {
|
resetRegistrationAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
context.commit(storeMutations.RESET_REGISTRATION_STATE);
|
||||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
|
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetPartsAndDependencies(context) {
|
resetPartsAndDependencies(context) {
|
||||||
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
|
||||||
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
|
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetState(context) {
|
resetState(context) {
|
||||||
context.commit(storeMutations.RESET_STATE);
|
context.commit(storeMutations.RESET_STATE);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetSaveSessionPromise(context) {
|
resetSaveSessionPromise(context) {
|
||||||
context.commit(storeMutations.RESET_SAVE_SESSION_PROMISE);
|
context.commit(storeMutations.RESET_SAVE_SESSION_PROMISE);
|
||||||
},
|
},
|
||||||
|
|
@ -699,12 +715,14 @@ export const actions = {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getHomepageName(context) {
|
getHomepageName(context) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetHomepageInfo.method,
|
method: endpoints.GetHomepageInfo.method,
|
||||||
endpoint: endpoints.GetHomepageInfo.url(applicationConfig.APPLICATION_ABBREVIATION),
|
endpoint: endpoints.GetHomepageInfo.url(applicationConfig.APPLICATION_ABBREVIATION),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getPageData(context, { pageName }) {
|
getPageData(context, { pageName }) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetPageData.method,
|
method: endpoints.GetPageData.method,
|
||||||
|
|
@ -771,6 +789,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
|
||||||
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
|
||||||
},
|
},
|
||||||
|
|
||||||
logPageView(
|
logPageView(
|
||||||
context,
|
context,
|
||||||
{
|
{
|
||||||
|
|
@ -812,6 +831,7 @@ export const actions = {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
logCustomEvent(
|
logCustomEvent(
|
||||||
context,
|
context,
|
||||||
{
|
{
|
||||||
|
|
@ -1116,52 +1136,123 @@ export const actions = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getShopTimeSlots(
|
getShopTimeSlots(context, { startDate, endDate, shopAppointmentType, providerNumber }) {
|
||||||
context,
|
|
||||||
{ startDate = "2023-01-01", endDate = "2023-05-01", shopAppointmentType = "" }
|
|
||||||
) {
|
|
||||||
const order = context.state.order;
|
const order = context.state.order;
|
||||||
const mockArray = [];
|
const vehicle = context.state.order.vehicle;
|
||||||
|
|
||||||
|
let partNumbers = [
|
||||||
|
...(order.lineItems.supportingItems ?? []),
|
||||||
|
...(order.lineItems.vaps ?? []),
|
||||||
|
...getFlattenedArrayOfLineItemsWithChildParts(order.lineItems.glassParts),
|
||||||
|
];
|
||||||
|
partNumbers = partNumbers.map((lineItem) => {
|
||||||
|
return lineItem.partNumber;
|
||||||
|
});
|
||||||
|
const glassPieces = order.damage.glassToReplace
|
||||||
|
? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace)
|
||||||
|
: [];
|
||||||
var payload = {
|
var payload = {
|
||||||
providerNumber: order.providerNumber,
|
providerNumber: providerNumber,
|
||||||
startDate: startDate,
|
startDate: startDate,
|
||||||
endDate: endDate,
|
endDate: endDate,
|
||||||
shopAppointmentType: shopAppointmentType,
|
shopAppointmentType: shopAppointmentType,
|
||||||
applicationName: applicationConfig.APPLICATION_NAME,
|
applicationName: "Safelite.com funnel",
|
||||||
parentAccountNumber: context.getters.payment.parentAccountNumber,
|
parentAccountNumber: context.getters.payment.parentAccountNumber,
|
||||||
carId: context.getters.vehicle.carId,
|
carId: vehicle.carId,
|
||||||
partNumbers: mockArray, // TODO: WHERE DO I GET THIS?
|
partNumbers: partNumbers,
|
||||||
|
glassPieces: glassPieces,
|
||||||
eon: order.eon,
|
eon: order.eon,
|
||||||
provisionalReasons: mockArray, // TODO: WHERE DO I GET THIS?
|
coverage: {
|
||||||
|
status: "",
|
||||||
|
deductible: 0,
|
||||||
|
additionalAuthFlag: "",
|
||||||
|
},
|
||||||
|
partSelection: {
|
||||||
|
// TODO: Provisional booking will utilize these fields
|
||||||
|
hasAnsweredPartQuestions: false,
|
||||||
|
hasAnsweredMoldingQuestions: false,
|
||||||
|
hasAnsweredCapabilityQuestions: false,
|
||||||
|
hasManuallySelectedParts: false,
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
year: vehicle.year,
|
||||||
|
make: vehicle.make,
|
||||||
|
model: vehicle.model,
|
||||||
|
style: vehicle.style,
|
||||||
|
vin: vehicle.vin ?? "",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: REMOVE MOCK CALL & USE REAL CALL BELOW
|
return globalMethods.callHttpClient({
|
||||||
return globalMethods.callMockHttpClient({
|
|
||||||
method: endpoints.GetShopTimeSlots.method,
|
method: endpoints.GetShopTimeSlots.method,
|
||||||
endpoint: endpoints.GetShopTimeSlots.mockUrl,
|
endpoint: endpoints.GetShopTimeSlots.url,
|
||||||
payload: payload,
|
payload: payload,
|
||||||
|
logApiCall: false,
|
||||||
});
|
});
|
||||||
// TODO: RESTORE THIS
|
|
||||||
// return globalMethods.callHttpClient({
|
|
||||||
// method: endpoints.GetShopTimeSlots.method,
|
|
||||||
// endpoint: endpoints.GetShopTimeSlots.url,
|
|
||||||
// payload: payload,
|
|
||||||
// logApiCall: false,
|
|
||||||
// });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getMobileTimeSlots(context, { startDate, endDate }) {
|
||||||
|
const order = context.state.order;
|
||||||
|
const vehicle = context.state.order.vehicle;
|
||||||
|
let partNumbers = [
|
||||||
|
...(order.lineItems.supportingItems ?? []),
|
||||||
|
...(order.lineItems.vaps ?? []),
|
||||||
|
...getFlattenedArrayOfLineItemsWithChildParts(order.lineItems.glassParts),
|
||||||
|
];
|
||||||
|
partNumbers = partNumbers.map((lineItem) => {
|
||||||
|
return lineItem.partNumber;
|
||||||
|
});
|
||||||
|
const glassPieces = order.damage.glassToReplace
|
||||||
|
? convertGlassPieceToBackEndCompatibleFormat(order.damage.glassToReplace)
|
||||||
|
: [];
|
||||||
|
var payload = {
|
||||||
|
startDate: startDate,
|
||||||
|
endDate: endDate,
|
||||||
|
applicationName: "Safelite.com funnel",
|
||||||
|
parentAccountNumber: context.getters.payment.parentAccountNumber,
|
||||||
|
carId: vehicle.carId,
|
||||||
|
partNumbers: partNumbers,
|
||||||
|
glassPieces: glassPieces,
|
||||||
|
eon: order.eon,
|
||||||
|
coverage: {
|
||||||
|
status: "",
|
||||||
|
deductible: 0,
|
||||||
|
additionalAuthFlag: "",
|
||||||
|
},
|
||||||
|
partSelection: {
|
||||||
|
// TODO: Provisional booking will utilize these fields
|
||||||
|
hasAnsweredPartQuestions: false,
|
||||||
|
hasAnsweredMoldingQuestions: false,
|
||||||
|
hasAnsweredCapabilityQuestions: false,
|
||||||
|
hasManuallySelectedParts: false,
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
year: vehicle.year,
|
||||||
|
make: vehicle.make,
|
||||||
|
model: vehicle.model,
|
||||||
|
style: vehicle.style,
|
||||||
|
vin: vehicle.vin ?? "",
|
||||||
|
},
|
||||||
|
zipCode: order.serviceLocation.zipCode,
|
||||||
|
};
|
||||||
|
return globalMethods.callHttpClient({
|
||||||
|
method: endpoints.GetMobileTimeSlots.method,
|
||||||
|
endpoint: endpoints.GetMobileTimeSlots.url,
|
||||||
|
payload: payload,
|
||||||
|
logApiCall: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getMobileEarlyBirdFee(context) {
|
getMobileEarlyBirdFee(context) {
|
||||||
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
|
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
|
||||||
const paymentType = context.getters.order.payment.isInsurance ? "Insurance" : "Cash";
|
const paymentType = context.getters.order.payment.isInsurance ? "Insurance" : "Cash";
|
||||||
return globalMethods.callMockHttpClient({
|
|
||||||
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.GetMobileEarlyBirdFee.method,
|
method: endpoints.GetMobileEarlyBirdFee.method,
|
||||||
endpoint: `${endpoints.GetMobileEarlyBirdFee.mockUrl}/Cash/Replace`,
|
endpoint: `${endpoints.GetMobileEarlyBirdFee.url}/${paymentType}/${damageType}`,
|
||||||
});
|
});
|
||||||
// return globalMethods.callHttpClient({
|
|
||||||
// method: endpoints.GetMobileEarlyBirdFee.method,
|
|
||||||
// endpoint: `${endpoints.GetMobileEarlyBirdFee.url}/${paymentType}/${damageType}`,
|
|
||||||
// });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Session API Actions
|
// Session API Actions
|
||||||
saveSession(context) {
|
saveSession(context) {
|
||||||
const vehicle = context.getters.vehicle;
|
const vehicle = context.getters.vehicle;
|
||||||
|
|
@ -1262,6 +1353,7 @@ export const actions = {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadSession(
|
loadSession(
|
||||||
context,
|
context,
|
||||||
{
|
{
|
||||||
|
|
@ -1339,6 +1431,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_YEAR, year);
|
context.commit(storeMutations.UPDATE_YEAR, year);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveVehicleMake(context, make) {
|
saveVehicleMake(context, make) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.make !== make) {
|
if (context.state.order.vehicle.make !== make) {
|
||||||
|
|
@ -1359,6 +1452,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_MAKE, make);
|
context.commit(storeMutations.UPDATE_MAKE, make);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveVehicleModel(context, model) {
|
saveVehicleModel(context, model) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.model !== model) {
|
if (context.state.order.vehicle.model !== model) {
|
||||||
|
|
@ -1378,6 +1472,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_MODEL, model);
|
context.commit(storeMutations.UPDATE_MODEL, model);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveVehicleStyle(context, style) {
|
saveVehicleStyle(context, style) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (context.state.order.vehicle.style !== style) {
|
if (context.state.order.vehicle.style !== style) {
|
||||||
|
|
@ -1396,6 +1491,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_STYLE, style);
|
context.commit(storeMutations.UPDATE_STYLE, style);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveVehicleDamage(
|
saveVehicleDamage(
|
||||||
context,
|
context,
|
||||||
{ isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }
|
{ isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }
|
||||||
|
|
@ -1453,6 +1549,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveRegistrationLicensePlateLookup(
|
saveRegistrationLicensePlateLookup(
|
||||||
context,
|
context,
|
||||||
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
||||||
|
|
@ -1474,6 +1571,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveRegistrationAddressLookup(
|
saveRegistrationAddressLookup(
|
||||||
context,
|
context,
|
||||||
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
|
||||||
|
|
@ -1499,6 +1597,7 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
savePartQuestionAnswers(context, partQuestionAnswersArray) {
|
||||||
// if part question answers have changed, reset subsequent question answers
|
// if part question answers have changed, reset subsequent question answers
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
|
|
@ -1537,6 +1636,7 @@ export const actions = {
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
|
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
|
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
|
||||||
const partsOrQuestionsDataToCompareWith =
|
const partsOrQuestionsDataToCompareWith =
|
||||||
context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ??
|
context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ??
|
||||||
|
|
@ -1576,6 +1676,7 @@ export const actions = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
|
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
context.getters.damage.moldingQuestionAnswers,
|
context.getters.damage.moldingQuestionAnswers,
|
||||||
|
|
@ -1604,6 +1705,7 @@ export const actions = {
|
||||||
//Save new values
|
//Save new values
|
||||||
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers);
|
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
|
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
|
||||||
context.getters.damage.capabilityQuestionAnswers,
|
context.getters.damage.capabilityQuestionAnswers,
|
||||||
|
|
@ -1630,18 +1732,23 @@ export const actions = {
|
||||||
capabilityQuestionAnswers
|
capabilityQuestionAnswers
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
savePaymentType(context, isInsurance) {
|
savePaymentType(context, isInsurance) {
|
||||||
context.commit(storeMutations.UPDATE_IS_INSURANCE, isInsurance);
|
context.commit(storeMutations.UPDATE_IS_INSURANCE, isInsurance);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveParentAccountNumber(context, parentAccountNumber) {
|
saveParentAccountNumber(context, parentAccountNumber) {
|
||||||
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber);
|
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveSupportingItems(context, supportingItems) {
|
saveSupportingItems(context, supportingItems) {
|
||||||
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
|
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveVaps(context, vaps) {
|
saveVaps(context, vaps) {
|
||||||
context.commit(storeMutations.UPDATE_VAPS, vaps);
|
context.commit(storeMutations.UPDATE_VAPS, vaps);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Price order actions
|
// Price order actions
|
||||||
async priceOrderItemsAndSaveServerData(
|
async priceOrderItemsAndSaveServerData(
|
||||||
context,
|
context,
|
||||||
|
|
@ -1694,16 +1801,20 @@ export const actions = {
|
||||||
|
|
||||||
return availableLineItems;
|
return availableLineItems;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Misc order actions
|
// Misc order actions
|
||||||
saveSchedule(context, scheduleInfo) {
|
saveSchedule(context, scheduleInfo) {
|
||||||
context.commit(storeMutations.UPDATE_SCHEDULE, scheduleInfo);
|
context.commit(storeMutations.UPDATE_SCHEDULE, scheduleInfo);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveServiceLocation(context, serviceLocationInfo) {
|
saveServiceLocation(context, serviceLocationInfo) {
|
||||||
context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo);
|
context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveEmail(context, email) {
|
saveEmail(context, email) {
|
||||||
context.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, email);
|
context.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, email);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {
|
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {
|
||||||
//Reset dependent state when changing
|
//Reset dependent state when changing
|
||||||
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
|
||||||
|
|
@ -1716,12 +1827,15 @@ export const actions = {
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo);
|
context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveGlassParts(context, parts) {
|
saveGlassParts(context, parts) {
|
||||||
context.commit(storeMutations.UPDATE_GLASS_PARTS, parts);
|
context.commit(storeMutations.UPDATE_GLASS_PARTS, parts);
|
||||||
},
|
},
|
||||||
|
|
||||||
clearVin(context) {
|
clearVin(context) {
|
||||||
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
isVinOptionalVehicle(context) {
|
isVinOptionalVehicle(context) {
|
||||||
switch (context.state.order.vehicle.make.toLowerCase()) {
|
switch (context.state.order.vehicle.make.toLowerCase()) {
|
||||||
case "mercedes benz":
|
case "mercedes benz":
|
||||||
|
|
@ -1863,7 +1977,7 @@ function addPricesToLineItems(lineItems, pricingLineItems) {
|
||||||
|
|
||||||
function getFlattenedArrayOfLineItemsWithChildParts(lineItems) {
|
function getFlattenedArrayOfLineItemsWithChildParts(lineItems) {
|
||||||
let flattenedArray = [];
|
let flattenedArray = [];
|
||||||
lineItems.forEach((lineItem) => {
|
lineItems?.forEach((lineItem) => {
|
||||||
flattenedArray.push(lineItem);
|
flattenedArray.push(lineItem);
|
||||||
if (lineItem.childParts) {
|
if (lineItem.childParts) {
|
||||||
flattenedArray = [
|
flattenedArray = [
|
||||||
|
|
@ -1885,3 +1999,12 @@ function buildQueryStringParameterFromArrayOfComplexObjects(arrayOfObjects, para
|
||||||
// Remove trailing &
|
// Remove trailing &
|
||||||
return queryStringParameter.slice(0, -1);
|
return queryStringParameter.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertGlassPieceToBackEndCompatibleFormat(glassPieces) {
|
||||||
|
return glassPieces.map((glassPiece) => {
|
||||||
|
return {
|
||||||
|
location: glassPiece.glassLocation,
|
||||||
|
name: glassPiece.glassName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
class="loader"
|
class="loader"
|
||||||
role="alert"
|
role="alert"
|
||||||
aria-label="Loading new page"
|
aria-label="Loading new page"
|
||||||
v-bind:class="[this.loaderColor, this.loaderPosition]"></div>
|
v-bind:class="[this.loaderColor, this.loaderPosition, this.blockUi]"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -19,6 +19,11 @@ export default {
|
||||||
loaderPosition: {
|
loaderPosition: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
|
/* Controls whether we block the UI when the loader is active or now, defaults to true*/
|
||||||
|
blockUi: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -82,5 +87,9 @@ export default {
|
||||||
&.black:after {
|
&.black:after {
|
||||||
background-color: $black;
|
background-color: $black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.no-block::before {
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue