diff --git a/jest.config.js b/jest.config.js
index a757d5ada..28c5557cb 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -26,7 +26,7 @@ module.exports = {
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
coverageThreshold: {
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
},
},
diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js
index 7d83642a6..53f981d8a 100644
--- a/src/constants/endpoints.js
+++ b/src/constants/endpoints.js
@@ -108,12 +108,14 @@ const endpoints = {
},
GetShopTimeSlots: {
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",
},
GetMobileEarlyBirdFee: {
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",
},
SaveSession: {
diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js
index 341fcd487..5ff98fd9d 100644
--- a/src/constants/store-actions.js
+++ b/src/constants/store-actions.js
@@ -33,6 +33,7 @@ const storeActions = {
GET_MOBILE_FEE_PART: "getMobileFeePart",
GET_SERVICEABILITY_DETAILS: "getServiceabilityDetails",
GET_SHOP_TIME_SLOTS: "getShopTimeSlots",
+ GET_MOBILE_TIME_SLOTS: "getMobileTimeSlots",
GET_PROVIDERS: "getProviders",
GET_MOBILE_EARLY_BIRD_FEE: "getMobileEarlyBirdFee",
SAVE_SESSION: "saveSession",
diff --git a/src/digital-components/button-question/button-question.vue b/src/digital-components/button-question/button-question.vue
index e8be5b145..7441ab422 100644
--- a/src/digital-components/button-question/button-question.vue
+++ b/src/digital-components/button-question/button-question.vue
@@ -257,7 +257,7 @@ export default {
watch: {
modelValue(newValue, oldValue) {
this.resetField({
- value: newValue
+ value: newValue,
});
},
answers() {
diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue
index 9154383cd..fefeb30ff 100644
--- a/src/digital-components/date-picker/date-picker.vue
+++ b/src/digital-components/date-picker/date-picker.vue
@@ -22,7 +22,6 @@
-
SundayS
MondayM
TuesdayT
@@ -84,7 +83,6 @@ export default {
months: null,
disableViewMoreDatesButton: false,
selectableDatesData: [], // NOTE: uses monthNum (1-based), NOT monthIndex (0-based)
- today: null,
hideSomeDaysForInitialView: null,
};
},
@@ -112,6 +110,12 @@ export default {
},
},
computed: {
+ today() {
+ if (this.todayOverrideDateString) {
+ return new Date(this.todayOverrideDateString);
+ }
+ return new Date();
+ },
todayMonthIndex() {
return this.today.getMonth() + 1;
},
@@ -151,39 +155,31 @@ export default {
this.$emit("date-clicked");
},
getWeekStartDate(date) {
- // Get the day of the week for date
- let dayOfWeek = date.getDay();
-
+ const dayOfWeek = date.getDay();
// Subtract the day of the week from date to get the date of Sunday
- let sunday = new Date(date);
+ const sunday = new Date(date);
sunday.setDate(sunday.getDate() - dayOfWeek);
-
- // Return the date of Sunday
return sunday;
},
getWeekEndDate(date) {
- const currentDay = date.getDay(); // Get the day of the week (0 = Sunday, 1 = Monday, etc.)
- const daysUntilSaturday = 6 - currentDay; // Calculate the number of days until Saturday
-
+ const dayOfWeek = date.getDay();
+ const daysUntilSaturday = 6 - dayOfWeek; // Calculate the number of days until Saturday
// Clone the given date and add the remaining days until Saturday
const saturday = new Date(date);
saturday.setDate(date.getDate() + daysUntilSaturday);
-
return saturday;
},
getNextWeekSunday(date) {
- const currentDay = date.getDay(); // Get the day of the week (0 = Sunday, 1 = Monday, etc.)
- const daysUntilNextSunday = currentDay === 0 ? 7 : 7 - currentDay; // Calculate the number of days until the next Sunday
-
+ const dayOfWeek = date.getDay();
+ const daysUntilNextSunday = 7 - dayOfWeek; // Calculate the number of days until the next Sunday
// Clone the given date and add the remaining days until Sunday
const nextSunday = new Date(date);
nextSunday.setDate(date.getDate() + daysUntilNextSunday);
-
return nextSunday;
},
getInitialViewWeeks(today, initialViewRowsToShow) {
- // TODO: this only is for future direction; create logic for past direction
- let weeks = [];
+ // TODO: this only is for future direction; need to create logic for past direction
+ const weeks = [];
let weekStartDate = this.getWeekStartDate(today);
let weekEndDate = this.getWeekEndDate(today);
for (let i = 0; i < initialViewRowsToShow; i++) {
@@ -200,14 +196,19 @@ export default {
return weeks;
},
async loadInitialData(config) {
- // CALLED FROM CONSUMING COMPONENT BEFORE DATE-PICKER APPEARS
- const todayDate = config.todayOverrideDateString
- ? new Date(config.todayOverrideDateString)
- : new Date();
+ let todayDate;
+ if (this.today) {
+ todayDate = this.today;
+ } else if (config.todayOverrideDateString) {
+ todayDate = new Date(config.todayOverrideDateString);
+ } else {
+ todayDate = new Date();
+ }
- let todayMonthIndex = todayDate.getMonth() + 1;
- let todayYearNum = todayDate.getFullYear();
- let currentMonthStart = new Date(todayYearNum, todayMonthIndex - 1, 1);
+ const todayMonthIndex = todayDate.getMonth() + 1;
+ const todayYearNum = todayDate.getFullYear();
+ // TODO - set up currentMonthStart if direction is PAST:
+ // let currentMonthStart = new Date(todayYearNum, todayMonthIndex - 1, 1);
let currentMonthEnd = new Date(todayYearNum, todayMonthIndex, 0);
let calendarViewDirection = "none";
@@ -219,10 +220,10 @@ export default {
config.initialViewRowsToShow
);
- let initialViewStartDate = todayDate;
- let initialViewEndDate = initialViewWeeks[initialViewWeeks.length - 1].weekEndDate;
- let saturday1month = initialViewWeeks[0].weekEndDate.getMonth();
- let sunday5month =
+ const initialViewStartDate = todayDate;
+ const initialViewEndDate = initialViewWeeks[initialViewWeeks.length - 1].weekEndDate;
+ const saturday1month = initialViewWeeks[0].weekEndDate.getMonth();
+ const sunday5month =
initialViewWeeks[initialViewWeeks.length - 1].weekStartDate.getMonth();
let hideSomeDaysForInitialView = false;
@@ -244,9 +245,10 @@ export default {
let myPromise = new Promise((resolve, reject) => {
const response = config.customSelectableDatesCallback(
- initialViewStartDate,
- initialViewEndDate,
- store.getters.order.serviceLocation.appointmentType
+ initialViewStartDate.toISOString().split("T")[0],
+ initialViewEndDate.toISOString().split("T")[0],
+ store.getters.order.serviceLocation.appointmentType,
+ store.getters.order.serviceLocation.provider.providerNumber
);
resolve(response);
});
@@ -284,9 +286,9 @@ export default {
// Growing from 0 to 1
time = Math.min(1, (timestamp - start) / duration);
- let percentageNew = timingFunc(time);
- let distanceToGo = targetY;
- let thisDistance = percentageNew * distanceToGo;
+ const percentageNew = timingFunc(time);
+ const distanceToGo = targetY;
+ const thisDistance = percentageNew * distanceToGo;
wrapper.scrollTo(0, initY + thisDistance);
@@ -305,13 +307,11 @@ export default {
},
async setCalendarData(config = {}) {
- this.today = config.todayDate;
this.hideSomeDaysForInitialView = config.hideSomeDaysForInitialView;
- let hideSecondMonth = config.hideSecondMonth;
+ const hideSecondMonth = config.hideSecondMonth;
const direction = config.calendarViewDirection;
-
- const monthsAfterToLoadOffset = 12; // TO BE MADE "CONSTANTS"
- const monthsBeforeToLoadOffset = 36; // TO BE MADE "CONSTANTS"
+ const monthsAfterToLoadOffset = 12;
+ const monthsBeforeToLoadOffset = 36;
config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
this.selectableDatesData.push(selectableDate);
});
@@ -382,25 +382,25 @@ export default {
}
}
- const monthEndDate = new Date(yearNum, monthIndex, 0); // BOTH
- let monthEndDateNum = monthEndDate.getDate(); // BOTH
+ const monthEndDate = new Date(yearNum, monthIndex, 0);
+ let monthEndDateNum = monthEndDate.getDate();
if (
offset === 0 &&
calendarViewDirection === "past" &&
monthEndDateNum > this.currentWeekEndDateNum
) {
- monthEndDateNum = this.currentWeekEndDateNum; // PAST
+ monthEndDateNum = this.currentWeekEndDateNum;
}
const monthStartDateNum =
offset === 0 && calendarViewDirection === "future"
? this.currentWeekStartDateNum
- : 1; // FUTURE
- const monthStartDate = new Date(yearNum, monthIndex - 1, monthStartDateNum); // BOTH
+ : 1;
+ const monthStartDate = new Date(yearNum, monthIndex - 1, monthStartDateNum);
- const startDateDayIndex = monthStartDate.getDay(); // FUTURE
- const endDateDayIndex = monthEndDate.getDay(); // PAST
+ const startDateDayIndex = monthStartDate.getDay();
+ const endDateDayIndex = monthEndDate.getDay();
if (Math.abs(offset) === 1 && hideSecondMonth) {
monthClass = monthClass + " month-hidden";
@@ -424,7 +424,7 @@ export default {
// populate dates array
for (let i = monthStartDateNum; i <= monthEndDateNum; i++) {
let dayClasses = "";
- let dateString =
+ const dateString =
yearNum.toString() +
"-" +
forceTwoDigitString(monthIndex) +
@@ -514,7 +514,7 @@ export default {
monthToShow.dates[monthToShow.dates.length - 1].inputValue.dateString
);
this.isLoading = false;
- this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this removes hidden styling on days
+ this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days
monthToShow.monthClass = monthToShow.monthClass.replace(" month-hidden", "");
this.scrollToElement(monthToShow.monthString);
@@ -526,7 +526,8 @@ export default {
const moreSelectableDates = await this.customSelectableDatesCallback(
monthStart,
monthEnd,
- this.$store.getters.order.serviceLocation.appointmentType
+ this.$store.getters.order.serviceLocation.appointmentType,
+ this.$store.getters.order.serviceLocation.provider.providerNumber
);
moreSelectableDates.days.forEach((selectableDate) => {
const index = this.selectableDatesData.findIndex(
diff --git a/src/digital-components/text-block/text-block.vue b/src/digital-components/text-block/text-block.vue
index 4f9c41599..2deb126e5 100644
--- a/src/digital-components/text-block/text-block.vue
+++ b/src/digital-components/text-block/text-block.vue
@@ -10,7 +10,7 @@ export default {
name: "textBlock",
props: {
customText: String, // used to allow the insert of token values into textblock
- justifyText: String, // left, right, center
+ justifyText: String, // right, center (left is default)
typeStyle: String, // h1-h6, body, small, label, caption (see Figma or Confluence documentation)
fontWeight: String, // bold=500, default is 400
cmsWidgetName: String,
@@ -28,15 +28,11 @@ export default {
diff --git a/src/layouts/quote/cash-or-insurance-question/cash-or-insurance-question.vue b/src/layouts/quote/cash-or-insurance-question/cash-or-insurance-question.vue
index 45fef683a..a2afb1a7c 100644
--- a/src/layouts/quote/cash-or-insurance-question/cash-or-insurance-question.vue
+++ b/src/layouts/quote/cash-or-insurance-question/cash-or-insurance-question.vue
@@ -5,7 +5,7 @@
:groupName="groupName"
buttonTypeString="listButtonHorizontal"
v-model="selectedValues"
- :additionalButtonData="{ additionalButtonStyling: 'listButtonHorizontalStrong' }"
+ :additionalButtonData="additionalButtonData"
isRequired />
@@ -27,6 +27,11 @@ export default {
answersFromCms() {
return this.getCmsContent(this.cmsWidgetName, "Answers");
},
+ additionalButtonData() {
+ return {
+ additionalButtonStyling: "listButtonHorizontalStrong",
+ };
+ },
selectedValues: {
get: function () {
// Convert to CMS answer name from bool
diff --git a/src/layouts/schedule/constants/schedule-constants.js b/src/layouts/schedule/constants/schedule-constants.js
new file mode 100644
index 000000000..89b4a4c1a
--- /dev/null
+++ b/src/layouts/schedule/constants/schedule-constants.js
@@ -0,0 +1,11 @@
+const AppointmentTypeStrings = {
+ IN_SHOP: "Inshop",
+ MOBILE: "Mobile",
+ DROP_OFF: "Dropoff",
+};
+
+const PREMIUM_TIME_SLOT_ID_FLAG = "-premium";
+
+const PREMIUM_FEE_PART_TYPE = "EARLY BIRD";
+
+export { AppointmentTypeStrings, PREMIUM_TIME_SLOT_ID_FLAG, PREMIUM_FEE_PART_TYPE };
diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue
index d5e3b4c28..37bdc8622 100644
--- a/src/layouts/schedule/schedule.vue
+++ b/src/layouts/schedule/schedule.vue
@@ -25,17 +25,17 @@
v-model="selectedDate"
:customSelectableDatesCallback="getAvailableDatesMethod"
@date-clicked="openInshopTimeSlotsModal" />
-
{
+const getAvailableDates = async (startDate, endDate, appointmentType, providerNumber) => {
// USING DATES PASSED, MAKE AN API CALL
- const newShopTimeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
- storeActions.GET_SHOP_TIME_SLOTS,
- {
- startDate: startDate,
- endDate: endDate,
- shopAppointmentType: appointmentType,
- },
- false
- );
- const newShopTimeSlots = newShopTimeSlotsResponse.data;
+
+ 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,
+ {
+ startDate: startDate,
+ endDate: endDate,
+ shopAppointmentType: appointmentType,
+ providerNumber: providerNumber,
+ },
+ false
+ );
+ }
+
+ const newShopTimeSlots = newTimeSlotsResponse.data;
return convertApiResponse(newShopTimeSlots);
};
const convertApiResponse = (responseData) => {
@@ -112,9 +128,12 @@ export default {
data() {
return {
selectedDate: null,
- selectedTimeSlotId: null,
+ selectedTimeSlotData: {
+ id: null,
+ isPremiumAppointment: null,
+ },
selectableDatesData: [],
- mobileEarlyBirdFee: null,
+ mobilePremiumAppointmentFee: null,
};
},
async beforeRouteEnter(to, from, next) {
@@ -125,40 +144,29 @@ export default {
selectableDatesSetting: "custom",
initialViewRowsToShow: 5,
customSelectableDatesCallback: getAvailableDates,
-
- /* vvvvv SAVE THESE FOR TESTING PURPOSES FOR NOW vvvvv
-
- // todayOverrideDateString: "2023-04-29T03:00:00", // show partial
- // todayOverrideDateString: "2023-04-30T03:00:00", //
- // todayOverrideDateString: "2023-05-02T03:00:00", // ONE MONTH ONLY
- // todayOverrideDateString: "2023-05-06T03:00:00", // ONE MONTH ONLY
- // todayOverrideDateString: "2023-05-07T03:00:00", // show partial
- // todayOverrideDateString: "2023-05-30T03:00:00", //
- // todayOverrideDateString: "2023-06-30T03:00:00", //
- // todayOverrideDateString: "2023-07-01T03:00:00", // show partial && ONE MONTH ONLY
- // todayOverrideDateString: "2023-07-02T03:00:00", // ONE MONTH ONLY
- // todayOverrideDateString: "2023-07-12T03:00:00", // show partial
- // todayOverrideDateString: "2023-08-31T03:00:00",
- // todayOverrideDateString: "2023-09-30T03:00:00", // show partial
- */
});
// Price EARLY BIRD pre-emptively to allow for asynchronous call to pricing
const pricingPromise = baseMixin.methods.dispatchStoreAction(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
- availableLineItems: [{ partNumber: "EARLY BIRD" }],
+ availableLineItems: [
+ {
+ partNumber: PREMIUM_FEE_PART_TYPE,
+ partType: PREMIUM_FEE_PART_TYPE,
+ description: null,
+ },
+ ],
},
false
);
- const earlyBirdPromise = baseMixin.methods.dispatchStoreAction(
+ const premiumFeePromise = baseMixin.methods.dispatchStoreAction(
storeActions.GET_MOBILE_EARLY_BIRD_FEE
);
const alertReasonsPromise = locationAlerts.methods.loadInitialData(
store.getters.order.serviceLocation.zipCodeCtu
);
-
// Settle promises and get results
const promiseResultMap = [
{
@@ -174,8 +182,8 @@ export default {
promise: datePickerInitialDataPromise,
},
{
- resultKey: "earlyBird",
- promise: earlyBirdPromise,
+ resultKey: "premiumFee",
+ promise: premiumFeePromise,
},
{
resultKey: "pricingResults",
@@ -191,8 +199,8 @@ export default {
vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
vm.selectableDatesData = resultMap.datePickerInitialData.initialShopTimeSlotsResponse;
- if (resultMap.earlyBird) {
- vm.mobileEarlyBirdFee = resultMap.pricingResults[0];
+ if (resultMap.premiumFee) {
+ vm.mobilePremiumAppointmentFee = resultMap.pricingResults[0];
}
});
},
@@ -216,18 +224,18 @@ export default {
);
},
appointmentDateAndTime() {
- if (!this.selectedTimeSlotId) {
+ if (!this.selectedTimeSlotData.id) {
return null;
}
const timeSlotSelectedObject = this.getTimeSlotObjectFromTimeSlotId(
- this.selectedTimeSlotId
+ this.selectedTimeSlotData.id
);
if (timeSlotSelectedObject) {
return {
date: this.selectedDate.dateString,
startTime: timeSlotSelectedObject.startTime,
endTime: timeSlotSelectedObject.endTime,
- id: this.selectedTimeSlotId,
+ id: this.selectedTimeSlotData.id,
};
} else {
return null;
@@ -247,7 +255,8 @@ export default {
const newShopTimeSlots = await getAvailableDates(
startDate,
endDate,
- this.appointmentType
+ this.appointmentType,
+ this.$store.getters.order.serviceLocation.provider.providerNumber
);
// ADD API CALL RESULTS TO EXISTING DATE DATA
this.selectableDatesData.days = this.selectableDatesData.days.concat(
@@ -268,11 +277,63 @@ export default {
return timeSlots.find((timeSlot) => timeSlot.id === timeSlotId);
},
timeSlotModalClosed() {
- // Clear the selectedDate if no timeslot has been selected
- if (!this.selectedTimeSlotId) {
+ // Clear the selectedDate if no timeSlot has been selected
+ if (!this.selectedTimeSlotData.id) {
this.selectedDate = null;
}
},
+ updateFooterButtonText(timeSlotData) {
+ let funnelFooterButtonText;
+ if (!timeSlotData.id) {
+ funnelFooterButtonText = "Continue";
+ } else {
+ funnelFooterButtonText =
+ "Select " + this.convertSelectedDateToShortMonthAndDay(this.selectedDate);
+
+ if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
+ funnelFooterButtonText +=
+ " at " +
+ this.getDisplayTextForMilitaryTime(this.appointmentDateAndTime.startTime);
+ } else if (
+ this.appointmentType === AppointmentTypeStrings.MOBILE &&
+ !timeSlotData.isPremiumAppointment
+ ) {
+ funnelFooterButtonText +=
+ " at " +
+ this.getDisplayTextForMilitaryTime(
+ this.appointmentDateAndTime.startTime,
+ true
+ ) +
+ " - " +
+ this.getDisplayTextForMilitaryTime(
+ this.appointmentDateAndTime.endTime,
+ true
+ );
+ }
+ }
+
+ this.$refs.funnelFooter.updateButtonText(funnelFooterButtonText);
+ },
+ convertSelectedDateToShortMonthAndDay(selectedDate) {
+ // This conversion ensures we don't get get GMT induced date changes
+ const dateObject = new Date(`${selectedDate.dateString}T00:00:00`);
+ // Ex: April 25
+ return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" });
+ },
+ // Expected input: "HH:MM:SS"
+ getDisplayTextForMilitaryTime(militaryTimeInput, shouldTrimMinutesIfEmpty = false) {
+ let hours = parseInt(militaryTimeInput.split(":")[0]);
+ const minutes = militaryTimeInput.split(":")[1];
+ let meridianNotation = hours > 11 ? "PM" : "AM";
+ if (hours > 12) {
+ hours -= 12;
+ }
+ if (shouldTrimMinutesIfEmpty && minutes === "00") {
+ return `${hours} ${meridianNotation}`;
+ } else {
+ return `${hours}:${minutes} ${meridianNotation}`;
+ }
+ },
backButtonAction() {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},
@@ -296,9 +357,15 @@ export default {
selectedDate(newValue, oldValue) {
// Clear time slot selection if date selected changes
if (newValue !== oldValue) {
- this.selectedTimeSlotId = null;
+ this.selectedTimeSlotData = {
+ id: null,
+ isPremiumAppointment: null,
+ };
}
},
+ selectedTimeSlotData() {
+ this.updateFooterButtonText(this.selectedTimeSlotData);
+ },
},
components: {
funnelHeader,
diff --git a/src/layouts/schedule/time-slot-modal-question/timeslot-modal-list-button/timeslot-modal-list-button.vue b/src/layouts/schedule/time-slot-modal-question/time-slot-modal-list-button/time-slot-modal-list-button.vue
similarity index 72%
rename from src/layouts/schedule/time-slot-modal-question/timeslot-modal-list-button/timeslot-modal-list-button.vue
rename to src/layouts/schedule/time-slot-modal-question/time-slot-modal-list-button/time-slot-modal-list-button.vue
index 60b2f9e81..44ac0d9e8 100644
--- a/src/layouts/schedule/time-slot-modal-question/timeslot-modal-list-button/timeslot-modal-list-button.vue
+++ b/src/layouts/schedule/time-slot-modal-question/time-slot-modal-list-button/time-slot-modal-list-button.vue
@@ -6,45 +6,32 @@
-
+
{{ buttonLabel }}
-
-
- {{ formattedButtonLabelSubCopy }}
+
+ {{ formattedButtonLabelSubCopy }}
+
{{ screenReaderOnlyText }}
-
diff --git a/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue b/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue
index a73ab712d..079df757d 100644
--- a/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue
+++ b/src/layouts/schedule/time-slot-modal-question/time-slot-modal-question.vue
@@ -14,12 +14,12 @@
typeStyle="small"
class="duration-text-block" />
@@ -41,7 +41,7 @@
import modal from "@/digital-components/modal/modal";
import textBlock from "@/digital-components/text-block/text-block";
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
import { DAYS_OF_WEEK, MONTHS_OF_YEAR } from "@/digital-components/date-picker/mixins/constants.js";
@@ -49,15 +49,17 @@ import { defineRule, useField } from "vee-validate";
import { errorMessages } from "@/constants/error-messages";
import { required } from "@/helpers/validation-rules";
+// Constants
+import {
+ AppointmentTypeStrings,
+ PREMIUM_TIME_SLOT_ID_FLAG,
+ PREMIUM_FEE_PART_TYPE,
+} from "../constants/schedule-constants";
+
// Validation for the modal button
defineRule("time-slot-required", required(errorMessages.OPTION_REQUIRED));
// Constants
-const AppointmentTypeStrings = {
- IN_SHOP: "Inshop",
- MOBILE: "Mobile",
- DROP_OFF: "Dropoff",
-};
export default {
name: "timeSlotModalQuestion",
@@ -65,19 +67,21 @@ export default {
modelValue: Object,
cmsWidgetName: String,
mobileCmsWidgetName: String,
- earlyBirdCmsWidgetName: String,
+ mobilePremiumCmsWidgetName: String,
dropoffCmsWidgetName: String,
+ sameDayDropOffCmsWidgetName: String,
appointmentType: String,
dateAndTimeSlotData: Object,
- mobileEarlyBirdFee: Object,
+ premiumAppointmentFee: Object,
estimatedServiceMinutesMinimum: Number,
estimatedServiceMinutesMaximum: Number,
validationRules: String,
},
data() {
return {
- selectedTimeSlot: null,
- timeslotModalListButton: timeslotModalListButton,
+ selectedTimeSlotId: null,
+ isSelectedAppointmentPremium: null,
+ timeSlotModalListButton: timeSlotModalListButton,
};
},
setup(props) {
@@ -89,42 +93,35 @@ export default {
},
watch: {
modelValue() {
- this.selectedTimeSlot = this.modelValue;
// Run component validation that is used at parent level
- this.handleChange(this.modelValue);
+ this.handleChange(this.modelValue.id);
+ },
+ dateAndTimeSlotData(newValue, oldValue) {
+ this.autoSelectTimeSlotIfOnlyOneIsAvailable(newValue);
},
- // dateAndTimeSlotData(newValue, oldValue) {
- // const numberOfOptions = newValue?.timeSlots.length;
- // console.log('running');
- // if (numberOfOptions === 1) {
- // this.selectedTimeSlot = newValue.timeSlots[0].id;
- // }
- // }
},
computed: {
supplementalInformationBlock() {
let appointmentTypeCmsWidgetName;
- let cmsFieldName = "BodyText";
if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
return null;
} else if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
appointmentTypeCmsWidgetName =
- this.selectedTimeSlot === this.earlyBirdButtonText
- ? this.earlyBirdCmsWidgetName
+ this.selectedTimeSlotId === this.premiumAppointmentButtonText
+ ? this.mobilePremiumCmsWidgetName
: this.mobileCmsWidgetName;
} else {
- appointmentTypeCmsWidgetName = this.dropoffCmsWidgetName;
- if (this.isSameDay) {
- cmsFieldName = "BodyText2";
- }
+ appointmentTypeCmsWidgetName = this.isSameDay
+ ? this.sameDayDropOffCmsWidgetName
+ : this.dropoffCmsWidgetName;
}
- return this.getCmsContent(appointmentTypeCmsWidgetName, cmsFieldName);
+ return this.getCmsContent(appointmentTypeCmsWidgetName, "BodyText");
},
footerCloseButtonText() {
return this.getCmsContent(this.cmsWidgetName, "FooterText");
},
- earlyBirdButtonText() {
- return this.getCmsContent(this.earlyBirdCmsWidgetName, "HeaderText");
+ premiumAppointmentButtonText() {
+ return this.getCmsContent(this.mobilePremiumCmsWidgetName, "HeaderText");
},
dropoffButtonText() {
return this.getCmsContent(this.dropoffCmsWidgetName, "HeaderText");
@@ -167,53 +164,24 @@ export default {
}
// 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}`;
+ // Ex: Tuesday, April 22
+ return dateObject.toLocaleDateString("en-us", {
+ weekday: "long",
+ month: "long",
+ day: "numeric",
+ });
},
availableTimeSlots() {
if (this.dateAndTimeSlotData === null) {
return null;
}
- let availableTimeSlots;
if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
- availableTimeSlots = [
- {
- value: this.dateAndTimeSlotData.timeSlots[0],
- buttonLabel: this.dropoffButtonText,
- },
- ];
+ return this.getAvailableTimeSlotsForDropOff(this.dateAndTimeSlotData.timeSlots);
+ } else if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
+ return this.getAvailableTimeSlotsForMobile(this.dateAndTimeSlotData.timeSlots);
} 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,
- };
- });
+ return this.getAvailableTimeSlotsForInshop(this.dateAndTimeSlotData.timeSlots);
}
-
- if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
- const offerPremium = this.dateAndTimeSlotData.timeSlots[0].offerPremium;
- const hasEarlyBird = this.mobileEarlyBirdFee?.partType === "EARLY BIRD";
- if (offerPremium && hasEarlyBird) {
- availableTimeSlots.unshift({
- value: this.dateAndTimeSlotData.timeSlots[0].id + "-earlybird",
- buttonLabel: this.earlyBirdButtonText,
- buttonLabelSubCopy: this.getTotalLineItemPrice(this.mobileEarlyBirdFee),
- });
- }
- }
- return availableTimeSlots;
},
},
methods: {
@@ -222,22 +190,36 @@ export default {
},
// fires any time the footer button is used, is fired before "onModalClosed"
closeModal() {
- this.$emit("update:modelValue", this.selectedTimeSlot);
+ if (this.selectedTimeSlotId.toString().includes(PREMIUM_TIME_SLOT_ID_FLAG)) {
+ this.selectedTimeSlotId = this.removePremiumFlagFromInput(this.selectedTimeSlotId);
+ this.isSelectedAppointmentPremium = true;
+ } else {
+ this.isSelectedAppointmentPremium = false;
+ }
+ const selectedTimeSlotData = {
+ id: this.selectedTimeSlotId,
+ isPremiumAppointment: this.isSelectedAppointmentPremium,
+ };
+ this.$emit("update:modelValue", selectedTimeSlotData);
this.$refs["timeSlots"].closeModal();
},
// fires any time the modal is closed, AFTER "closeModal" fires if footer button is used
onModalClosed() {
- this.selectedTimeSlot = this.modelValue;
+ this.isSelectedAppointmentPremium = this.modelValue.isPremiumAppointment;
+ if (this.isSelectedAppointmentPremium) {
+ this.selectedTimeSlotId = this.addPremiumFlagToInput(this.modelValue.id);
+ } else {
+ this.selectedTimeSlotId = this.modelValue.id;
+ }
this.$emit("time-slot-modal-closed");
},
// Expected input: "HH:MM:SS"
getDisplayTextForMilitaryTime(militaryTimeInput) {
let hours = parseInt(militaryTimeInput.split(":")[0]);
const minutes = militaryTimeInput.split(":")[1];
- let meridianNotation = "AM";
- if (militaryTimeInput.split(":")[0] > 12) {
+ let meridianNotation = hours > 11 ? "PM" : "AM";
+ if (hours > 12) {
hours -= 12;
- meridianNotation = "PM";
}
return `${hours}:${minutes} ${meridianNotation}`;
},
@@ -252,6 +234,77 @@ export default {
}
return displayTextForDurationLength;
},
+ getAvailableTimeSlotsForInshop(timeSlotsForSelectedDate) {
+ return timeSlotsForSelectedDate.map((timeSlot) => {
+ const readableTime = this.getDisplayTextForMilitaryTime(timeSlot.startTime);
+ return {
+ value: timeSlot.id,
+ buttonLabel: readableTime,
+ };
+ });
+ },
+ getAvailableTimeSlotsForDropOff(timeSlotsForSelectedDate) {
+ 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 and the premium appoinment shares a timeSlot ID
+ value: this.addPremiumFlagToInput(timeSlotData.id),
+ buttonLabel: this.premiumAppointmentButtonText,
+ buttonLabelSubCopy: formattedPrice,
+ additionalButtonData: {
+ isPremiumAppointment: true,
+ },
+ };
+ },
+ autoSelectTimeSlotIfOnlyOneIsAvailable(newdateAndTimeSlotDataValue) {
+ const numberOfOptions = newdateAndTimeSlotDataValue?.timeSlots.length;
+ if (
+ numberOfOptions === 1 &&
+ !(
+ this.appointmentType === AppointmentTypeStrings.MOBILE &&
+ this.premiumAppointmentFee &&
+ newdateAndTimeSlotDataValue.timeSlots[0].offerPremium
+ )
+ ) {
+ this.selectedTimeSlotId = newdateAndTimeSlotDataValue.timeSlots[0].id;
+ }
+ },
+ addPremiumFlagToInput(timeSlotId) {
+ return (timeSlotId += PREMIUM_TIME_SLOT_ID_FLAG);
+ },
+ removePremiumFlagFromInput(timeSlotId) {
+ return parseInt(timeSlotId.trim(PREMIUM_TIME_SLOT_ID_FLAG.length));
+ },
},
components: {
modal,
diff --git a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js
index 53f4e5797..f998b3188 100644
--- a/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js
+++ b/src/layouts/service-location/helpers/service-location-helper/service-location-helper.js
@@ -44,7 +44,7 @@ export async function getServiceabilityDetails(serviceZipCode, lineItems) {
return Promise.resolve(serviceabilityDetails);
}
-export async function getAvailabilityRating(providerNumber, startDate, endDate, appointmentType) {
+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,
@@ -52,7 +52,7 @@ export async function getAvailabilityRating(providerNumber, startDate, endDate,
providerNumber: providerNumber,
startDate: startDate,
endDate: endDate,
- shopAppointmentType: appointmentType,
+ shopAppointmentType: shopAppointmentType,
},
false
);
diff --git a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
index 48642101c..fa5c1eb62 100644
--- a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
+++ b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
@@ -236,6 +236,17 @@ export default {
});
},
async setMobileLocation() {
+ // START - TEMP CODE FROM A CAOUETTE 5/25/23 TO BE REMOVED BY EOD
+ let tempTest = false;
+ let internalModelAddressQuestions = this.internalModel.addressQuestions;
+ let modelValueAddressQuestions = this.modelValue.addressQuestions;
+ if (tempTest) {
+ // THIS WILL NEVER BE TRUE
+ console.warn(internalModelAddressQuestions);
+ console.warn(modelValueAddressQuestions);
+ }
+ // END - TEMP CODE FROM A CAOUETTE 5/25/23 TO BE REMOVED BY EOD
+
if (
this.internalModel.addressQuestions.zipCode !==
this.modelValue.addressQuestions.zipCode
@@ -270,6 +281,13 @@ export default {
this.closeModal();
}
+ } else {
+ // START - TEMP CODE FROM A CAOUETTE 5/25/23 TO BE REMOVED BY EOD
+ if (tempTest) {
+ // THIS WILL NEVER BE TRUE
+ console.warn("the zips match and the exception was run");
+ }
+ // END - TEMP CODE FROM A CAOUETTE 5/25/23 TO BE REMOVED BY EOD
}
},
},
diff --git a/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue b/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue
index b430f3af7..32573651f 100644
--- a/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue
+++ b/src/layouts/service-location/shop-question/shop-list-button/shop-list-button.vue
@@ -52,9 +52,14 @@ export default {
props: {
loaderColor: String,
},
- async beforeMount() {
+ beforeMount() {
this.displayLoader();
- this.additionalButtonData.availabilityRatingCallback(this.modelValue).then((data) => {
+ console.log(this.value)
+ const startDate = this.additionalButtonData.startDate;
+ 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;
});
@@ -66,7 +71,7 @@ export default {
availabilityRating: "None",
availabilityRatingClass: "",
loaderPosition: "left",
- blockUi: "no-block"
+ blockUi: "no-block",
};
},
methods: {
diff --git a/src/layouts/service-location/shop-question/shop-question.vue b/src/layouts/service-location/shop-question/shop-question.vue
index 0bb9e4237..5da8598a4 100644
--- a/src/layouts/service-location/shop-question/shop-question.vue
+++ b/src/layouts/service-location/shop-question/shop-question.vue
@@ -106,8 +106,18 @@ export default {
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,
};
},
},
@@ -208,11 +218,11 @@ export default {
},
watch: {
selectedAppointmentType: {
- async handler(newValue) {
+ async handler(newValue) {
this.resetAnswers();
await nextTick();
-
+
this.selectedProviderNumber = null;
await nextTick();
@@ -225,7 +235,7 @@ export default {
shopProviders: {
async handler(newValue) {
await nextTick();
-
+
if (this.selectedAppointmentType) {
const selectedShopIndex = this.getSelectedProviderIndex(
newValue,
diff --git a/src/router/index.js b/src/router/index.js
index 3abfa058d..15ba52647 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -28,21 +28,7 @@ import analyticsMixin from "@/mixins/analytics-mixin";
import { experimentTriggers } from "../constants/experiments";
import { applicationConfig } from "../constants/application-config";
-// Components
-import datePicker from "@/digital-components/date-picker/date-picker.vue";
-import demoDatePicker from "@/layouts/demo-date-picker/demo-date-picker.vue";
-
const routes = [
- {
- path: "/demo-date-picker", // This is a temporary route for testing.
- name: "demo-date-picker",
- component: demoDatePicker,
- },
- {
- path: "/date-picker", // This is a temporary route for testing.
- name: "date-picker",
- component: datePicker,
- },
{
path: "/",
name: "root",
diff --git a/src/store/index.js b/src/store/index.js
index a119d6978..b97c826c7 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1136,57 +1136,121 @@ export const actions = {
});
},
- getShopTimeSlots(
- context,
- {
- providerNumber = null,
- startDate = "2023-01-01",
- endDate = "2023-05-01",
- shopAppointmentType = "",
- }
- ) {
+ getShopTimeSlots(context, { startDate, endDate, shopAppointmentType, providerNumber }) {
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 ?? [];
var payload = {
- providerNumber: providerNumber ?? order.providerNumber,
+ providerNumber: providerNumber,
startDate: startDate,
endDate: endDate,
shopAppointmentType: shopAppointmentType,
- applicationName: applicationConfig.APPLICATION_NAME,
+ applicationName: "Safelite.com funnel",
parentAccountNumber: context.getters.payment.parentAccountNumber,
- carId: context.getters.vehicle.carId,
- partNumbers: mockArray, // TODO: WHERE DO I GET THIS?
+ carId: vehicle.carId,
+ partNumbers: partNumbers,
+ glassPieces: glassPieces,
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.callMockHttpClient({
+ console.log(payload)
+
+ return globalMethods.callHttpClient({
method: endpoints.GetShopTimeSlots.method,
- endpoint: endpoints.GetShopTimeSlots.mockUrl,
+ 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 ?? [];
+ 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,
});
- // TODO: RESTORE THIS
- // return globalMethods.callHttpClient({
- // method: endpoints.GetShopTimeSlots.method,
- // endpoint: endpoints.GetShopTimeSlots.url,
- // payload: payload,
- // logApiCall: false,
- // });
},
getMobileEarlyBirdFee(context) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
const paymentType = context.getters.order.payment.isInsurance ? "Insurance" : "Cash";
- return globalMethods.callMockHttpClient({
+
+ return globalMethods.callHttpClient({
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
@@ -1913,7 +1977,7 @@ function addPricesToLineItems(lineItems, pricingLineItems) {
function getFlattenedArrayOfLineItemsWithChildParts(lineItems) {
let flattenedArray = [];
- lineItems.forEach((lineItem) => {
+ lineItems?.forEach((lineItem) => {
flattenedArray.push(lineItem);
if (lineItem.childParts) {
flattenedArray = [
diff --git a/src/ux-components/loader/loader.vue b/src/ux-components/loader/loader.vue
index d890fdbfe..f304b79fa 100644
--- a/src/ux-components/loader/loader.vue
+++ b/src/ux-components/loader/loader.vue
@@ -21,8 +21,8 @@ export default {
},
blockUi: {
type: Boolean,
- default: true
- }
+ default: true,
+ },
},
};