Update scrollTo to use fade-on-route-transition.

This commit is contained in:
Bryan Mauger 2024-04-25 16:27:41 -04:00
parent 19d7347a3c
commit 946b0a69a2
3 changed files with 193 additions and 115 deletions

View file

@ -2,21 +2,21 @@
<div
class="date-picker text-center"
:class="[calendarViewDirection, { 'has-error': errors.length > 0 }]">
<fieldset
id="date-picker-fieldset"
ref="datePickerFieldset">
<legend class="sr-only">
Select a day and time
</legend>
<fieldset id="date-picker-fieldset" ref="datePickerFieldset">
<legend class="sr-only">Select a day and time</legend>
<div
v-for="month in months"
:id="`${month.monthLabel}-${month.yearNum?.toString()}`"
:key="`${month.monthLabel}-${month.yearNum?.toString()}`"
class="calendar-grid-container"
:class="[
hideSomeDaysForInitialView ? 'partial-month-initial-view' : '',
month.monthClass,]">
<div class="month-year body-small d-flex align-items-center small">
hideSomeDaysForInitialView
? 'partial-month-initial-view'
: '',
month.monthClass
]">
<div
class="month-year body-small d-flex align-items-center small">
{{ month.monthLabel }} {{ month.yearNum?.toString() }}
</div>
<div
@ -58,9 +58,12 @@
:key="date.inputValue"
class="grid-item radio-wrapper"
:class="[
date.dateNum === 1 ? 'first-day-' + month.startDateDayIndex : '',
date.dateNum === 1
? 'first-day-' + month.startDateDayIndex
: '',
date.dayClasses,
date.isSelectable ? 'selectable-day' : '',]">
date.isSelectable ? 'selectable-day' : ''
]">
<input
:id="`${month.monthLabel}-${date.dateNum.toString()}`"
v-model="selectedDate"
@ -70,7 +73,8 @@
:value="date.inputValue"
@click="fireDateSelectedEvent"
@keypress.enter="fireDateSelectedEvent" />
<label :for="`${month.monthLabel}-${date.dateNum.toString()}`">
<label
:for="`${month.monthLabel}-${date.dateNum.toString()}`">
<span>{{ date.dateNum.toString() }}</span>
</label>
</div>
@ -79,16 +83,15 @@
:class="[!isLoading ? 'date-picker-hidden' : '']"
loaderColor="blue"
loaderPosition="center" />
<div
id="date-of-month-error"
class="row form-test-error">
<ErrorMessage
:name="customComponentId"
class="small mt-1">
<div id="date-of-month-error" class="row form-test-error">
<ErrorMessage :name="customComponentId" class="small mt-1">
</ErrorMessage>
</div>
<button
v-if="calendarViewDirection === 'future' && !disableViewMoreDatesButton"
v-if="
calendarViewDirection === 'future' &&
!disableViewMoreDatesButton
"
id="viewMoreDates"
type="button"
class="btn btn-link"
@ -106,8 +109,15 @@ import loader from '@/ux-components/loader/loader.vue';
import { useMainStore } from '@/store';
import { useField, ErrorMessage } from 'vee-validate';
import { deepClone } from '@/helpers/object-helper';
import { convertDateStringToDate, convertDateToDateString } from '@/helpers/date-helper';
import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from './mixins/constants';
import {
convertDateStringToDate,
convertDateToDateString
} from '@/helpers/date-helper';
import {
TIMINGFUNC_MAP,
BUFFER_OFFSET,
MONTHS_OF_YEAR
} from './mixins/constants';
import { selectableDaysOptions, requiredParameter } from './mixins/helpers';
export default {
@ -161,8 +171,15 @@ export default {
initialValue
};
const { errorMessage, handleBlur, handleChange, meta, validate, errors, resetField } =
useField(componentId, props.validationRules, fieldOptions);
const {
errorMessage,
handleBlur,
handleChange,
meta,
validate,
errors,
resetField
} = useField(componentId, props.validationRules, fieldOptions);
return {
componentId,
@ -187,7 +204,10 @@ export default {
},
computed: {
todayString() {
return this.todayOverrideDateString || convertDateToDateString(new Date());
return (
this.todayOverrideDateString ||
convertDateToDateString(new Date())
);
},
todayDayIndex() {
return convertDateStringToDate(this.todayString).getDay();
@ -268,17 +288,27 @@ export default {
},
getMonthEnd(dateStr) {
// convert string to date, do date calc, then return a string back
const date = new Date(dateStr.split('-')[0], parseInt(dateStr.split('-')[1], 10), 0);
const date = new Date(
dateStr.split('-')[0],
parseInt(dateStr.split('-')[1], 10),
0
);
return convertDateToDateString(date);
},
getInitialViewWeeks(todayString, initialViewRowsToShow, preSelectedDateString) {
getInitialViewWeeks(
todayString,
initialViewRowsToShow,
preSelectedDateString
) {
// TODO: this only is for future direction; need to create logic for past direction
const weeks = [];
let weekStartDate = this.getWeekStartDate(todayString);
let weekEndDate = this.getWeekEndDate(todayString);
if (preSelectedDateString) {
const preSelectedDateMonthEnd = this.getMonthEnd(preSelectedDateString);
const preSelectedDateMonthEnd = this.getMonthEnd(
preSelectedDateString
);
let weekIncludesPreSelectedMonthEnd = false;
let i = 0;
while (!weekIncludesPreSelectedMonthEnd) {
@ -287,10 +317,10 @@ export default {
weekEndDate = this.getWeekEndDate(weekStartDate);
if (
(preSelectedDateMonthEnd > weekStartDate
&& preSelectedDateMonthEnd < weekEndDate)
|| preSelectedDateMonthEnd === weekStartDate
|| preSelectedDateMonthEnd === weekEndDate
(preSelectedDateMonthEnd > weekStartDate &&
preSelectedDateMonthEnd < weekEndDate) ||
preSelectedDateMonthEnd === weekStartDate ||
preSelectedDateMonthEnd === weekEndDate
) {
weekEndDate = preSelectedDateMonthEnd;
weekIncludesPreSelectedMonthEnd = true;
@ -317,7 +347,9 @@ export default {
}
// If any of these weeks is split between two months, then make them 2 separate "weeks"
// (a week split between two months is considered 2 weeks per business requirements)
const hasSplitWeek = (week) => (week.weekStartDate.split('-')[1] !== week.weekEndDate.split('-')[1]);
const hasSplitWeek = (week) =>
week.weekStartDate.split('-')[1] !==
week.weekEndDate.split('-')[1];
const splitWeekIndex = weeks.findIndex(hasSplitWeek);
if (splitWeekIndex > -1) {
@ -326,7 +358,9 @@ export default {
let switchToWeek2 = false;
for (let j = 0; j < 7; j++) {
const newDate = convertDateStringToDate(weeks[splitWeekIndex].weekStartDate);
const newDate = convertDateStringToDate(
weeks[splitWeekIndex].weekStartDate
);
newDate.setDate(newDate.getDate() + j);
if (newDate.getDate() === 1) switchToWeek2 = true;
if (switchToWeek2) {
@ -377,8 +411,10 @@ export default {
} else {
todayDateString = convertDateToDateString(new Date());
}
if (config.selectableDatesSetting === 'past') calendarViewDirection = 'past';
if (config.selectableDatesSetting === 'custom') calendarViewDirection = 'future';
if (config.selectableDatesSetting === 'past')
calendarViewDirection = 'past';
if (config.selectableDatesSetting === 'custom')
calendarViewDirection = 'future';
const currentMonthEnd = this.getMonthEnd(todayDateString);
// TODO - set up currentMonthStart if direction is PAST:
@ -389,18 +425,24 @@ export default {
config.preSelectedDate
);
const initialViewStartDate = todayDateString;
const initialViewEndDate = initialViewWeeks[initialViewWeeks.length - 1].weekEndDate;
const initialViewEndDate =
initialViewWeeks[initialViewWeeks.length - 1].weekEndDate;
if (!config.preSelectedDate) {
const firstSaturdayMonth = initialViewWeeks[0].weekEndDate.split('-')[1];
const firstSaturdayMonth =
initialViewWeeks[0].weekEndDate.split('-')[1];
const lastSundayMonth =
initialViewWeeks[initialViewWeeks.length - 1].weekStartDate.split('-')[1];
initialViewWeeks[
initialViewWeeks.length - 1
].weekStartDate.split('-')[1];
if (calendarViewDirection === 'future') {
if (firstSaturdayMonth !== lastSundayMonth) {
hideSomeDaysForInitialView = true;
}
if (initialViewStartDate.split('-')[1] === lastSundayMonth) {
if (
initialViewStartDate.split('-')[1] === lastSundayMonth
) {
hideSecondMonth = true;
if (currentMonthEnd > initialViewEndDate) {
// should part of 1st month be hidden?
@ -441,9 +483,11 @@ export default {
const direction = config.calendarViewDirection;
const monthsAfterToLoadOffset = 6;
const monthsBeforeToLoadOffset = 36;
config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
this.selectableDatesData.push(selectableDate);
});
config.initialShopTimeSlotsResponse.days.forEach(
(selectableDate) => {
this.selectableDatesData.push(selectableDate);
}
);
// GENERATE MONTHS AND PUSH THEM INTO ARRAY
const months = [];
@ -479,10 +523,11 @@ export default {
this.$nextTick(() => {
// Advance to month
const monthToShow = this.months.find((month) =>
month.monthClass.includes('month-preselected'));
month.monthClass.includes('month-preselected')
);
if (
monthToShow.monthClass.includes('month-preselected')
&& monthToShow.monthClass.includes('last-available-month')
monthToShow.monthClass.includes('month-preselected') &&
monthToShow.monthClass.includes('last-available-month')
) {
// disable View More dates button if the preSelectedDate in the last available month
this.disableViewMoreDatesButton = true;
@ -506,8 +551,13 @@ export default {
this.hideSomeDaysForInitialView (string)
*/
let monthNum = convertDateStringToDate(this.todayString).getMonth() + offset + 1;
let yearNum = convertDateStringToDate(this.todayString).getFullYear();
let monthNum =
convertDateStringToDate(this.todayString).getMonth() +
offset +
1;
let yearNum = convertDateStringToDate(
this.todayString
).getFullYear();
const { calendarViewDirection } = options;
if (calendarViewDirection === 'future' && offset > 0) {
while (monthNum > 12) {
@ -532,7 +582,11 @@ export default {
offset === 0 && calendarViewDirection === 'future'
? this.currentWeekStartDateNum
: 1;
const monthStartDate = new Date(yearNum, monthNum - 1, monthStartDateNum);
const monthStartDate = new Date(
yearNum,
monthNum - 1,
monthStartDateNum
);
const startDateDayIndex = monthStartDate.getDay();
let monthClass = '';
@ -540,17 +594,18 @@ export default {
let monthEndDateNum = monthEndDate.getDate();
if (
offset === 0
&& calendarViewDirection === 'past'
&& monthEndDateNum > this.currentWeekEndDateNum
offset === 0 &&
calendarViewDirection === 'past' &&
monthEndDateNum > this.currentWeekEndDateNum
) {
monthEndDateNum = this.currentWeekEndDateNum;
}
if (options.preSelectedDate) {
if (
monthStartDate.getFullYear() === preSelectedDateObj.getFullYear()
&& monthStartDate.getMonth() === preSelectedDateObj.getMonth()
monthStartDate.getFullYear() ===
preSelectedDateObj.getFullYear() &&
monthStartDate.getMonth() === preSelectedDateObj.getMonth()
) {
monthClass += ' month-preselected';
} else if (monthStartDate > preSelectedDateObj) {
@ -563,14 +618,14 @@ export default {
}
if (
Math.abs(offset) === options.monthsAfterToLoadOffset
&& calendarViewDirection === 'future'
Math.abs(offset) === options.monthsAfterToLoadOffset &&
calendarViewDirection === 'future'
) {
monthClass += ' last-available-month';
}
if (
Math.abs(offset) === options.monthsBeforeToLoadOffset
&& calendarViewDirection === 'past'
Math.abs(offset) === options.monthsBeforeToLoadOffset &&
calendarViewDirection === 'past'
) {
// TODO - re-check this logic if past direction
monthClass += ' last-available-month';
@ -579,29 +634,36 @@ export default {
// populate dates array
for (let i = monthStartDateNum; i <= monthEndDateNum; i++) {
let dayClasses = '';
const dateString =
`${yearNum.toString()
}-${
(`0${monthNum}`).slice(-2)
}-${
(`0${i}`).slice(-2)}`;
const dateString = `${yearNum.toString()}-${`0${monthNum}`.slice(
-2
)}-${`0${i}`.slice(-2)}`;
if (offset === 0 && i === this.todayDateNum) {
dayClasses += ' current-day';
}
if (offset === 0 && i < this.todayDateNum && calendarViewDirection === 'future') {
if (
offset === 0 &&
i < this.todayDateNum &&
calendarViewDirection === 'future'
) {
dayClasses += ' unavailable-day';
}
if (offset === 0 && i > this.todayDateNum && calendarViewDirection === 'past') {
if (
offset === 0 &&
i > this.todayDateNum &&
calendarViewDirection === 'past'
) {
dayClasses += ' unavailable-day';
}
if (convertDateStringToDate(dateString).getDay() === 0) {
dayClasses += ' sunday';
}
if (
this.hideSomeDaysForInitialView
&& convertDateStringToDate(initialViewEndDate).getMonth() + 1 === monthNum
&& convertDateStringToDate(initialViewEndDate).getDate() < i
this.hideSomeDaysForInitialView &&
convertDateStringToDate(initialViewEndDate).getMonth() +
1 ===
monthNum &&
convertDateStringToDate(initialViewEndDate).getDate() < i
) {
dayClasses += ' day-hidden';
isMonthThatHidesSomeDaysForInitialView = true;
@ -611,7 +673,9 @@ export default {
dayClasses,
inputValue: dateString,
isSelectable:
this.selectableDatesData.findIndex((date) => date.date === dateString) > -1
this.selectableDatesData.findIndex(
(date) => date.date === dateString
) > -1
};
dates.push(dateObject);
}
@ -619,7 +683,9 @@ export default {
const monthToAdd = {
monthLabel: MONTHS_OF_YEAR[monthNum - 1],
monthIndex: monthNum,
monthString: `${MONTHS_OF_YEAR[monthNum - 1]}-${yearNum?.toString()}`,
monthString: `${
MONTHS_OF_YEAR[monthNum - 1]
}-${yearNum?.toString()}`,
yearNum,
dates,
startDateDayIndex,
@ -634,21 +700,26 @@ export default {
let monthStartDateNum = 0;
if (this.hideSomeDaysForInitialView) {
monthToShow = this.months.find(({ isMonthThatHidesSomeDaysForInitialView }) =>
isMonthThatHidesSomeDaysForInitialView);
monthToShow = this.months.find(
({ isMonthThatHidesSomeDaysForInitialView }) =>
isMonthThatHidesSomeDaysForInitialView
);
// find the first day-hidden to become the next api call start date
monthStartDateNum =
monthToShow.dates.find(({ dayClasses }) => dayClasses.includes('day-hidden'))
.dateNum - 1;
monthToShow.dates.find(({ dayClasses }) =>
dayClasses.includes('day-hidden')
).dateNum - 1;
} else {
if (this.calendarViewDirection === 'future') {
monthToShow = this.months.find((month) =>
month.monthClass.includes('month-hidden'));
month.monthClass.includes('month-hidden')
);
}
if (this.calendarViewDirection === 'past') {
// TODO: UPDATE THIS WITH CORRECT PAST LOOKING LOGIC
monthToShow = this.months.find((month) =>
month.monthClass.includes('month-hidden'));
month.monthClass.includes('month-hidden')
);
}
}
if (monthToShow) {
@ -659,22 +730,29 @@ export default {
);
this.isLoading = false;
this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days
monthToShow.monthClass = monthToShow.monthClass.replace(' month-hidden', '');
monthToShow.monthClass = monthToShow.monthClass.replace(
' month-hidden',
''
);
this.scrollToElement(monthToShow.monthString);
if (monthToShow.monthClass.includes('last-available-month')) this.disableViewMoreDatesButton = true;
if (monthToShow.monthClass.includes('last-available-month'))
this.disableViewMoreDatesButton = true;
}
},
async updateSelectableDates(monthStart, monthEnd) {
const moreSelectableDates = await this.customSelectableDatesCallback(
monthStart,
monthEnd,
this.mainStore.order.serviceLocation.appointmentType,
this.mainStore.order.serviceLocation.provider.providerNumber
);
const moreSelectableDates =
await this.customSelectableDatesCallback(
monthStart,
monthEnd,
this.mainStore.order.serviceLocation.appointmentType,
this.mainStore.order.serviceLocation.provider.providerNumber
);
moreSelectableDates.days.forEach((selectableDate) => {
const index = this.selectableDatesData.findIndex((dateObj) => dateObj.date === selectableDate.date);
const index = this.selectableDatesData.findIndex(
(dateObj) => dateObj.date === selectableDate.date
);
if (index === -1) this.selectableDatesData.push(selectableDate);
this.months.forEach((month) => {
// TODO: avoid checking all calendar dates; maybe only ones between monthStart and monthEnd as defined above?
@ -687,7 +765,7 @@ export default {
});
},
scrollToElement(elementId, duration = 800, easing = 'ease-in-out') {
const wrapper = document.querySelector('.page-container-grouped-styles');
const wrapper = document.querySelector('.fade-on-route-transition');
const target = document.getElementById(elementId);
const initY = wrapper.scrollTop;
const wrapperRect = wrapper.getBoundingClientRect();
@ -713,7 +791,7 @@ export default {
</script>
<style lang="scss" scoped>
@import "@/styles/ux-variables-svg-strings.scss";
@import '@/styles/ux-variables-svg-strings.scss';
.date-picker-hidden {
opacity: 0;
@ -821,7 +899,7 @@ export default {
opacity: 1;
transition: height ease 250ms, opacity ease 250ms;
input[type="radio"] {
input[type='radio'] {
position: absolute; //override bootstrap
height: 0;
opacity: 0;
@ -929,7 +1007,7 @@ export default {
&.unavailable-day:not(&.sunday) {
label {
&::before {
content: "";
content: '';
display: inline-block;
position: absolute;
left: -1rem;
@ -945,7 +1023,7 @@ export default {
color: $black;
&:after {
content: "";
content: '';
width: 0.25rem;
height: 0.25rem;
border-radius: 50%;
@ -997,7 +1075,7 @@ export default {
justify-content: flex-end;
button {
&:after {
content: "";
content: '';
position: absolute;
width: 7px;
height: 12px;
@ -1011,7 +1089,7 @@ export default {
justify-content: flex-end;
button {
&:after {
content: "";
content: '';
position: absolute;
width: 7px;
height: 12px;

View file

@ -125,7 +125,7 @@ import { useMainStore } from '@/store';
import {
getPricedMobileFeePart,
getServiceabilityDetails,
getZipCodeData,
getZipCodeData
} from '@/helpers/service-location-helper';
// Import Component
@ -168,7 +168,7 @@ export default {
// eslint-disable-next-line vue/no-reserved-component-names
Form,
serviceZipModalQuestion,
shopQuestion,
shopQuestion
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
@ -190,24 +190,24 @@ export default {
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise,
promise: cmsContentPromise
},
{
resultKey: 'mobileFeePart',
promise: mobileFeePartPromise,
promise: mobileFeePartPromise
},
{
resultKey: 'serviceabilityDetails',
promise: serviceabilityDetailsPromise,
promise: serviceabilityDetailsPromise
},
{
resultKey: 'shopQuestionInitialData',
promise: shopQuestionInitialDataPromise,
promise: shopQuestionInitialDataPromise
},
{
resultKey: 'zipCodeData',
promise: zipCodeData,
},
promise: zipCodeData
}
];
const resultMap = await settleAllPromises(promiseResultMap);
@ -245,7 +245,7 @@ export default {
mobileFeePart: null,
mobileProviderNumber: null,
zipContainsMilitaryBase: false,
zipCodeCtu: null,
zipCodeCtu: null
};
},
computed: {
@ -262,7 +262,7 @@ export default {
get() {
return {
state: this.state,
zipCode: this.zipCode,
zipCode: this.zipCode
};
},
set(newValue) {
@ -277,7 +277,7 @@ export default {
// eslint-disable-next-line vue/valid-next-tick
this.$nextTick();
},
}
},
mobileLocationQuestions: {
get() {
@ -287,9 +287,9 @@ export default {
streetAddress2: this.streetAddress2,
city: this.city,
state: this.state,
zipCode: this.zipCode,
zipCode: this.zipCode
},
isVehicleProtected: this.isVehicleProtected,
isVehicleProtected: this.isVehicleProtected
};
},
set(newValue) {
@ -313,7 +313,7 @@ export default {
}
this.selectedProvider = null;
}
},
}
},
isServiceableMobile() {
if (this.isRecalibrationServiceableMobile !== null) {
@ -383,7 +383,7 @@ export default {
return isNoComp || isITAC
? this.navigationScenarios.CLICKED_BACK_CANNOT_REACH_TPA_FLOW
: this.navigationScenarios.CLICKED_BACK_CAN_REACH_TPA_FLOW;
},
}
},
methods: {
arePagePrerequisitesValid() {
@ -410,8 +410,8 @@ export default {
city: null,
state: null,
zipCode: null,
zipCodeCtu: null,
},
zipCodeCtu: null
}
};
}
@ -424,7 +424,7 @@ export default {
zipCodeCtu: this.zipCodeCtu,
appointmentType: this.selectedAppointmentType,
isVehicleProtected: this.isVehicleProtected,
provider,
provider
});
this.$router.navigate(
@ -516,15 +516,15 @@ export default {
serviceabilityDetails.isGlassServiceableMobile;
this.isRecalibrationServiceableMobile =
serviceabilityDetails.isRecalibrationServiceableMobile;
},
},
}
}
};
</script>
<style lang="scss" scoped>
$page-side-padding: 1.5rem;
.page-container-grouped-styles {
.fade-on-route-transition {
overflow: auto;
.main-content-container {

View file

@ -11,8 +11,8 @@ body {
.prevent-squish {
overflow-x: unset;
}
&.page-container-grouped-styles {
overflow: hidden;
&.fade-on-route-transition {
height: 100vh;
display: flex;
flex-direction: column;
}