Merge branch 'develop' into feature/CSR-1144

This commit is contained in:
CarlNation 2023-06-05 15:48:38 -04:00
commit 4e732d19a9
11 changed files with 120 additions and 88 deletions

View file

@ -31,8 +31,8 @@
<div class="grid-item caption"><span class="sr-only">Saturday</span>S</div> <div class="grid-item caption"><span class="sr-only">Saturday</span>S</div>
<div <div
v-for="date in month.dates" v-for="date in month.dates"
:key="date.inputValue.dateString" :key="date.inputValue"
:id="date.inputValue.dateString" :id="date.inputValue"
class="grid-item radio-wrapper" class="grid-item radio-wrapper"
:class="[ :class="[
date.dateNum === 1 ? 'first-day-' + month.startDateDayIndex : '', date.dateNum === 1 ? 'first-day-' + month.startDateDayIndex : '',
@ -193,6 +193,51 @@ export default {
weekEndDate: weekEndDate, weekEndDate: weekEndDate,
}); });
} }
// are any of these weeks split between two months?
const hasSplitWeek = (week) => {
return week.weekStartDate.getMonth() !== week.weekEndDate.getMonth() ? true : false;
};
const splitWeekIndex = weeks.findIndex(hasSplitWeek);
if (splitWeekIndex > -1) {
const week1 = [];
const week2 = [];
let switchToWeek2 = false;
for (let j = 0; j < 7; j++) {
const newDate = new Date(weeks[splitWeekIndex].weekStartDate);
newDate.setDate(newDate.getDate() + j);
if (newDate.getDate() === 1) switchToWeek2 = true;
if (switchToWeek2) {
week2.push(newDate);
} else {
week1.push(newDate);
}
}
const week1EndDate = week1[week1.length - 1];
const week2StartDate = week2[0];
if (week1EndDate < today) {
// replace week 1 with week 2
weeks[splitWeekIndex].weekStartDate = week2StartDate;
} else {
const newWeek = {
weekNum: weeks[splitWeekIndex].weekNum,
weekStartDate: week2StartDate,
weekEndDate: weeks[splitWeekIndex].weekEndDate,
};
weeks[splitWeekIndex].weekEndDate = week1EndDate;
weeks.splice(splitWeekIndex + 1, 0, newWeek);
weeks.pop();
weeks.forEach((item, index) => {
if (index > splitWeekIndex) {
item.weekNum = item.weekNum + 1;
}
});
}
}
return weeks; return weeks;
}, },
async loadInitialData(config) { async loadInitialData(config) {
@ -209,7 +254,7 @@ export default {
const todayYearNum = todayDate.getFullYear(); const todayYearNum = todayDate.getFullYear();
// TODO - set up currentMonthStart if direction is PAST: // TODO - set up currentMonthStart if direction is PAST:
// let currentMonthStart = new Date(todayYearNum, todayMonthIndex - 1, 1); // let currentMonthStart = new Date(todayYearNum, todayMonthIndex - 1, 1);
let currentMonthEnd = new Date(todayYearNum, todayMonthIndex, 0); const currentMonthEnd = new Date(todayYearNum, todayMonthIndex, 0);
let calendarViewDirection = "none"; let calendarViewDirection = "none";
if (config.selectableDatesSetting === "past") calendarViewDirection = "past"; if (config.selectableDatesSetting === "past") calendarViewDirection = "past";
@ -222,8 +267,8 @@ export default {
const initialViewStartDate = todayDate; const initialViewStartDate = todayDate;
const initialViewEndDate = initialViewWeeks[initialViewWeeks.length - 1].weekEndDate; const initialViewEndDate = initialViewWeeks[initialViewWeeks.length - 1].weekEndDate;
const saturday1month = initialViewWeeks[0].weekEndDate.getMonth(); const firstSaturdayMonth = initialViewWeeks[0].weekEndDate.getMonth();
const sunday5month = const lastSundayMonth =
initialViewWeeks[initialViewWeeks.length - 1].weekStartDate.getMonth(); initialViewWeeks[initialViewWeeks.length - 1].weekStartDate.getMonth();
let hideSomeDaysForInitialView = false; let hideSomeDaysForInitialView = false;
@ -231,10 +276,10 @@ export default {
// TODO - NEED TO CREATE OPPOSITE LOGIC FOR "past" DIRECTION LIKE BELOW vvvvv // TODO - NEED TO CREATE OPPOSITE LOGIC FOR "past" DIRECTION LIKE BELOW vvvvv
if (calendarViewDirection === "future") { if (calendarViewDirection === "future") {
if (saturday1month !== sunday5month) { if (firstSaturdayMonth !== lastSundayMonth) {
hideSomeDaysForInitialView = true; hideSomeDaysForInitialView = true;
} }
if (initialViewStartDate.getMonth() === sunday5month) { if (initialViewStartDate.getMonth() === lastSundayMonth) {
hideSecondMonth = true; hideSecondMonth = true;
if (currentMonthEnd > initialViewEndDate) { if (currentMonthEnd > initialViewEndDate) {
// should part of 1st month be hidden? // should part of 1st month be hidden?
@ -243,7 +288,7 @@ export default {
} }
} }
let myPromise = new Promise((resolve, reject) => { const myPromise = new Promise((resolve, reject) => {
const response = config.customSelectableDatesCallback( const response = config.customSelectableDatesCallback(
initialViewStartDate.toISOString().split("T")[0], initialViewStartDate.toISOString().split("T")[0],
initialViewEndDate.toISOString().split("T")[0], initialViewEndDate.toISOString().split("T")[0],
@ -431,12 +476,6 @@ export default {
"-" + "-" +
forceTwoDigitString(i); forceTwoDigitString(i);
const thisDate = {
year: yearNum,
month: monthIndex,
date: i,
dateString: dateString,
};
if (offset === 0 && i === this.todayDateNum) { if (offset === 0 && i === this.todayDateNum) {
dayClasses += "current-day"; dayClasses += "current-day";
} }
@ -457,11 +496,9 @@ export default {
const dateObject = { const dateObject = {
dateNum: i, dateNum: i,
dayClasses: dayClasses, dayClasses: dayClasses,
inputValue: thisDate, inputValue: dateString,
isSelectable: isSelectable:
this.selectableDatesData.findIndex( this.selectableDatesData.findIndex((date) => date.date === dateString) > -1
(date) => date.dateString === dateString
) > -1
? true ? true
: false, : false,
}; };
@ -510,8 +547,8 @@ export default {
if (monthToShow) { if (monthToShow) {
// make new API call with this month's start and end dates // make new API call with this month's start and end dates
await this.updateSelectableDates( await this.updateSelectableDates(
monthToShow.dates[monthStartDateNum].inputValue.dateString, monthToShow.dates[monthStartDateNum].inputValue,
monthToShow.dates[monthToShow.dates.length - 1].inputValue.dateString monthToShow.dates[monthToShow.dates.length - 1].inputValue
); );
this.isLoading = false; this.isLoading = false;
this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days
@ -531,13 +568,13 @@ export default {
); );
moreSelectableDates.days.forEach((selectableDate) => { moreSelectableDates.days.forEach((selectableDate) => {
const index = this.selectableDatesData.findIndex( const index = this.selectableDatesData.findIndex(
(obj) => obj.dateString === selectableDate.dateString (dateObj) => dateObj.date === selectableDate.date
); );
if (index === -1) this.selectableDatesData.push(selectableDate); if (index === -1) this.selectableDatesData.push(selectableDate.date);
this.months.forEach((month) => { this.months.forEach((month) => {
// TODO: avoid checking all calendar date; maybe only ones between monthStart and monthEnd as defined above? // TODO: avoid checking all calendar dates; maybe only ones between monthStart and monthEnd as defined above?
month.dates.forEach((date) => { month.dates.forEach((date) => {
if (date.inputValue.dateString === selectableDate.dateString) { if (date.inputValue === selectableDate.date) {
date["isSelectable"] = true; date["isSelectable"] = true;
} }
}); });
@ -808,7 +845,6 @@ export default {
.btn-link { .btn-link {
font-weight: 500; font-weight: 500;
text-underline-offset: 4px; text-underline-offset: 4px;
box-shadow: none !important; // TODO: FIX THIS
position: absolute; position: absolute;
top: 90%; top: 90%;
} }

View file

@ -73,7 +73,7 @@ import {
getRouterLinkRouteFromCopy, getRouterLinkRouteFromCopy,
getRouterLinkDisplayTextFromCopy, getRouterLinkDisplayTextFromCopy,
} from "@/helpers/cms-content-helper"; } from "@/helpers/cms-content-helper";
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "./constants/schedule-constants"; import { AppointmentTypeStrings } from "./constants/schedule-constants";
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
import { required } from "@/helpers/validation-rules"; import { required } from "@/helpers/validation-rules";
import store from "@/store"; import store from "@/store";
@ -107,20 +107,7 @@ const getAvailableDates = async (startDate, endDate, appointmentType, providerNu
); );
} }
const newShopTimeSlots = newTimeSlotsResponse.data; return newTimeSlotsResponse.data;
return convertApiResponse(newShopTimeSlots);
};
const convertApiResponse = (responseData) => {
// DATA CONVERSION
responseData?.days.forEach((date) => {
const dateString = date.date;
date.dateString = dateString;
const dateStringPieces = dateString.split("-");
date.year = Number(dateStringPieces[0]);
date.month = Number(dateStringPieces[1]);
date.date = Number(dateStringPieces[2]);
});
return responseData;
}; };
export default { export default {
@ -146,24 +133,24 @@ export default {
customSelectableDatesCallback: getAvailableDates, customSelectableDatesCallback: getAvailableDates,
}); });
// 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: PREMIUM_FEE_PART_TYPE,
partType: PREMIUM_FEE_PART_TYPE,
description: null,
},
],
},
false
);
const premiumFeePromise = baseMixin.methods.dispatchStoreAction( const premiumFeePromise = baseMixin.methods.dispatchStoreAction(
storeActions.GET_MOBILE_PREMIUM_FEE storeActions.GET_MOBILE_PREMIUM_FEE
); );
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
if (result.data) {
return baseMixin.methods.dispatchStoreAction(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
availableLineItems: [result.data],
},
false
);
} else {
return result.data;
}
});
const alertReasonsPromise = locationAlerts.methods.loadInitialData( const alertReasonsPromise = locationAlerts.methods.loadInitialData(
store.getters.order.serviceLocation.zipCodeCtu store.getters.order.serviceLocation.zipCodeCtu
); );
@ -182,12 +169,8 @@ export default {
promise: datePickerInitialDataPromise, promise: datePickerInitialDataPromise,
}, },
{ {
resultKey: "premiumFee", resultKey: "premiumFeeWithPrice",
promise: premiumFeePromise, promise: premiumFeeWithPricePromise,
},
{
resultKey: "pricingResults",
promise: pricingPromise,
}, },
]; ];
@ -199,9 +182,10 @@ export default {
vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData); vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons); vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
vm.selectableDatesData = resultMap.datePickerInitialData.initialShopTimeSlotsResponse; vm.selectableDatesData = resultMap.datePickerInitialData.initialShopTimeSlotsResponse;
if (resultMap.premiumFee) { vm.mobilePremiumAppointmentFee = resultMap.premiumFeeWithPrice
vm.mobilePremiumAppointmentFee = resultMap.pricingResults[0]; ? resultMap.premiumFeeWithPrice[0]
} : null;
vm.updateFooterButtonText(vm.selectedTimeSlotData);
}); });
}, },
computed: { computed: {
@ -216,11 +200,11 @@ export default {
return this.$store.getters.order.serviceLocation.appointmentType; return this.$store.getters.order.serviceLocation.appointmentType;
}, },
timeSlotsForSelectedDate() { timeSlotsForSelectedDate() {
if (this.selectedDate === null) { if (!this.selectedDate) {
return null; return null;
} }
return this.selectableDatesData.days?.find( return this.selectableDatesData.days?.find(
(selectableDate) => selectableDate.dateString === this.selectedDate.dateString (selectableDate) => selectableDate.date === this.selectedDate
); );
}, },
appointmentDateAndTime() { appointmentDateAndTime() {
@ -230,10 +214,9 @@ 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,
startTime: timeSlotSelectedObject.startTime, startTime: timeSlotSelectedObject.startTime,
endTime: timeSlotSelectedObject.endTime, endTime: timeSlotSelectedObject.endTime,
routeCode: this.selectedTimeSlotData.id, routeCode: this.selectedTimeSlotData.id,
@ -275,7 +258,7 @@ export default {
}, },
getTimeSlotObjectFromTimeSlotId(timeSlotId) { getTimeSlotObjectFromTimeSlotId(timeSlotId) {
const timeSlots = this.selectableDatesData.days.find( const timeSlots = this.selectableDatesData.days.find(
(selectableDate) => selectableDate.dateString === this.selectedDate.dateString (selectableDate) => selectableDate.date === this.selectedDate
).timeSlots; ).timeSlots;
return timeSlots.find((timeSlot) => timeSlot.id === timeSlotId); return timeSlots.find((timeSlot) => timeSlot.id === timeSlotId);
}, },
@ -325,7 +308,7 @@ 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}T00:00:00`);
// Ex: April 25 // Ex: April 25
return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" }); return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" });
}, },
@ -365,7 +348,7 @@ export default {
}; };
} }
}, },
selectedTimeSlotData() { selectedTimeSlotData(newValue) {
this.updateFooterButtonText(this.selectedTimeSlotData); this.updateFooterButtonText(this.selectedTimeSlotData);
}, },
}, },

View file

@ -78,13 +78,14 @@ export default {
}, },
data() { data() {
return { return {
selectedTimeSlotId: null, selectedTimeSlotId: this.modelValue.id,
timeSlotModalListButton: timeSlotModalListButton, timeSlotModalListButton: timeSlotModalListButton,
}; };
}, },
setup(props) { setup(props) {
const { handleChange } = useField("time-slot-modal-question", props.validationRules); const { handleChange } = useField("time-slot-modal-question", props.validationRules);
// Run validation on component load
handleChange(props.modelValue.id);
return { return {
handleChange, handleChange,
}; };
@ -92,6 +93,11 @@ export default {
watch: { watch: {
modelValue() { modelValue() {
// Run component validation that is used at parent level // Run component validation that is used at parent level
if (this.modelValue.isPremiumAppointment) {
this.selectedTimeSlotId = this.addPremiumFlagToInput(this.modelValue.id);
} else {
this.selectedTimeSlotId = this.modelValue.id;
}
this.handleChange(this.modelValue.id); this.handleChange(this.modelValue.id);
}, },
availableTimeSlots(newValue) { availableTimeSlots(newValue) {
@ -162,7 +168,7 @@ export default {
} }
// 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(`${this.dateAndTimeSlotData.dateString}T00:00:00`); const dateObject = new Date(`${this.dateAndTimeSlotData.date}T00:00:00`);
// Ex: Tuesday, April 22 // Ex: Tuesday, April 22
return dateObject.toLocaleDateString("en-us", { return dateObject.toLocaleDateString("en-us", {
weekday: "long", weekday: "long",
@ -203,12 +209,6 @@ export default {
}, },
// 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() {
// Reset component state to parent's state
if (this.modelValue.isPremiumAppointment) {
this.selectedTimeSlotId = this.addPremiumFlagToInput(this.modelValue.id);
} else {
this.selectedTimeSlotId = this.modelValue.id;
}
this.$emit("time-slot-modal-closed"); this.$emit("time-slot-modal-closed");
}, },
// Expected input: "HH:MM" // Expected input: "HH:MM"

View file

@ -142,7 +142,7 @@ export default {
city: this.getServiceCityFromStore(), city: this.getServiceCityFromStore(),
state: this.getServiceStateFromStore(), state: this.getServiceStateFromStore(),
zipCode: this.getServiceZipCodeFromStore(), zipCode: this.getServiceZipCodeFromStore(),
isVehicleProtected: null, isVehicleProtected: this.getIsVehicleProtectedFromStore(),
isGlassServiceableInshop: null, isGlassServiceableInshop: null,
isRecalibrationServiceableInshop: null, isRecalibrationServiceableInshop: null,
isGlassServiceableMobile: null, isGlassServiceableMobile: null,
@ -348,6 +348,9 @@ export default {
getServiceZipCodeFromStore() { getServiceZipCodeFromStore() {
return store.getters.order.serviceLocation.zipCode; return store.getters.order.serviceLocation.zipCode;
}, },
getIsVehicleProtectedFromStore() {
return store.getters.order.serviceLocation.isVehicleProtected;
},
getSelectedAppointmentType() { getSelectedAppointmentType() {
return store.getters.order.serviceLocation.appointmentType; return store.getters.order.serviceLocation.appointmentType;
}, },

View file

@ -192,7 +192,7 @@ export default {
.button-auxillary-copy { .button-auxillary-copy {
box-sizing: border-box; box-sizing: border-box;
justify-content: right; justify-content: right;
line-height: 1.25rem !important; line-height: 1.25rem;
font-weight: 500; font-weight: 500;
font-size: 0.75rem; font-size: 0.75rem;
align-items: center; align-items: center;
@ -205,7 +205,7 @@ export default {
} }
.loader:after { .loader:after {
background-color: $gray-300 !important; background-color: $gray-300;
height: 1rem; height: 1rem;
width: 1rem; width: 1rem;
} }
@ -221,7 +221,7 @@ export default {
} }
&.gray { &.gray {
color: $gray-600 !important; color: $gray-600;
background-color: $gray-100; background-color: $gray-100;
padding-left: 0.125rem; padding-left: 0.125rem;
padding-right: 0.125rem; padding-right: 0.125rem;

View file

@ -280,7 +280,7 @@ export default {
border-radius: 0.5rem; border-radius: 0.5rem;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
padding: 0.5rem 0.5rem 0.5rem 1.5rem !important; padding: 0.5rem 0.5rem 0.5rem 1.5rem;
gap: 0.25rem; gap: 0.25rem;
.alert-heading { .alert-heading {

View file

@ -39,11 +39,13 @@ const getDefaultState = () => {
}, },
serviceLocation: { serviceLocation: {
address: null, address: null,
address2: null,
city: null, city: null,
state: null, state: null,
zipCode: null, zipCode: null,
zipCodeCtu: null, zipCodeCtu: null,
appointmentType: null, appointmentType: null,
isVehicleProtected: null,
provider: { provider: {
providerNumber: null, providerNumber: null,
address: { address: {
@ -1190,7 +1192,6 @@ export const actions = {
method: endpoints.GetShopTimeSlots.method, method: endpoints.GetShopTimeSlots.method,
endpoint: endpoints.GetShopTimeSlots.url, endpoint: endpoints.GetShopTimeSlots.url,
payload: payload, payload: payload,
logApiCall: false,
}); });
}, },
@ -1242,7 +1243,6 @@ export const actions = {
method: endpoints.GetMobileTimeSlots.method, method: endpoints.GetMobileTimeSlots.method,
endpoint: endpoints.GetMobileTimeSlots.url, endpoint: endpoints.GetMobileTimeSlots.url,
payload: payload, payload: payload,
logApiCall: false,
}); });
}, },

View file

@ -56,3 +56,9 @@ body {
height: calc(100% - 72px); height: calc(100% - 72px);
} }
} }
//Disable scroll of main container when modal is open
.modal-open {
.page-container-grouped-styles {
overflow: hidden;
}
}

View file

@ -9,6 +9,7 @@
position: relative; position: relative;
z-index: 5; z-index: 5;
@include box-shadow-hover($blue-300); @include box-shadow-hover($blue-300);
border-radius: 0.5rem;
} }
} }
} }

View file

@ -190,3 +190,6 @@ $alert-color-scale: 40%;
// This affects all [Bootstrap] modals // This affects all [Bootstrap] modals
$modal-fade-transform: translate(0, 100%); $modal-fade-transform: translate(0, 100%);
$modal-backdrop-opacity: 0; $modal-backdrop-opacity: 0;
//Disable default !important behavior
$enable-important-utilities: false;

View file

@ -94,7 +94,7 @@ export default {
+ .list-card-content { + .list-card-content {
outline: none; outline: none;
display: block; display: flex;
position: relative; position: relative;
p { p {