Merge pull request #2426 from Safelite/CASH-499-calendar-ui-updates
Cash 499 calendar UI updates
This commit is contained in:
commit
f06da57711
7 changed files with 184 additions and 1259 deletions
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<div class="date-picker text-center" :class="calendarViewDirection">
|
||||
<div
|
||||
class="date-picker text-center"
|
||||
:class="`${calendarViewDirection} ${isPricingByDayClass} ${showPricingByDayClass}`">
|
||||
<fieldset id="date-picker-fieldset" ref="datePickerFieldset">
|
||||
<legend class="sr-only">Select a day and time</legend>
|
||||
<div
|
||||
|
|
@ -60,18 +62,24 @@
|
|||
date.dateNum === 1 ? 'first-day-' + month.startDateDayIndex : '',
|
||||
date.dayClasses,
|
||||
date.isSelectable ? 'selectable-day' : '',
|
||||
date.isPricingByDayUpchargeDay ? 'upch-day' : '',
|
||||
]">
|
||||
<input
|
||||
:disabled="!date.isSelectable"
|
||||
type="radio"
|
||||
name="day-of-month"
|
||||
v-model="selectedDate"
|
||||
@click="fireDateSelectedEvent"
|
||||
@keypress.enter="fireDateSelectedEvent"
|
||||
@click="fireDateSelectedEvent($event, date)"
|
||||
@keypress.enter="fireDateSelectedEvent($event, date)"
|
||||
:value="date.inputValue"
|
||||
:id="`${month.monthLabel}-${date.dateNum.toString()}`" />
|
||||
<label :for="`${month.monthLabel}-${date.dateNum.toString()}`">
|
||||
<span>{{ date.dateNum.toString() }}</span>
|
||||
<span
|
||||
v-if="isPricingByDayExperiment && showPricingByDay && date.isSelectable"
|
||||
class="price">
|
||||
{{ date.priceString }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -99,8 +107,17 @@
|
|||
// Supporting files
|
||||
import loader from "@/ux-components/loader/loader";
|
||||
import store from "@/store";
|
||||
import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from "./mixins/constants";
|
||||
import { selectableDaysOptions, requiredParameter, forceTwoDigitString } from "./mixins/helpers";
|
||||
import {
|
||||
TIMINGFUNC_MAP,
|
||||
BUFFER_OFFSET,
|
||||
MONTHS_OF_YEAR,
|
||||
DAYS_OF_WEEK,
|
||||
} from "@/digital-components/date-picker/mixins/constants";
|
||||
import {
|
||||
selectableDaysOptions,
|
||||
requiredParameter,
|
||||
forceTwoDigitString,
|
||||
} from "@/digital-components/date-picker/mixins/helpers";
|
||||
import {
|
||||
convertDateToDateString,
|
||||
convertDateStringToDate,
|
||||
|
|
@ -148,6 +165,10 @@ export default {
|
|||
type: String,
|
||||
default: "",
|
||||
},
|
||||
showPricingByDay: Boolean,
|
||||
pricingByDayBasePrice: Number,
|
||||
pricingByDayUpcharge: Number,
|
||||
isPricingByDayExperiment: Boolean,
|
||||
},
|
||||
setup(props) {
|
||||
const uuid = uuidv4();
|
||||
|
|
@ -199,6 +220,12 @@ export default {
|
|||
if (this.selectableDatesSetting === "custom") return "future";
|
||||
return "past";
|
||||
},
|
||||
isPricingByDayClass() {
|
||||
return this.isPricingByDayExperiment ? "pricing-by-day" : "";
|
||||
},
|
||||
showPricingByDayClass() {
|
||||
return this.showPricingByDay ? "show-pricing-by-day" : "";
|
||||
},
|
||||
selectedDate: {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
|
|
@ -212,12 +239,12 @@ export default {
|
|||
initializeComponent(initialData) {
|
||||
this.setCalendarData(initialData);
|
||||
},
|
||||
fireDateSelectedEvent(event) {
|
||||
fireDateSelectedEvent(event, date) {
|
||||
// Ignore if arrow key selected radioButton
|
||||
if (event.screenX === 0 && event.screenY === 0) {
|
||||
return;
|
||||
}
|
||||
this.$emit("date-clicked");
|
||||
this.$emit("date-clicked", date);
|
||||
},
|
||||
getWeekStartDate(dateString) {
|
||||
const date = convertDateStringToDate(dateString);
|
||||
|
|
@ -440,6 +467,8 @@ export default {
|
|||
initialViewEndDate: config.initialViewEndDate,
|
||||
hideSecondMonth: hideSecondMonth,
|
||||
preSelectedDate: config.preSelectedDate,
|
||||
pricingByDayBasePrice: config.pricingByDayBasePrice,
|
||||
pricingByDayUpcharge: config.pricingByDayUpcharge,
|
||||
};
|
||||
if (direction === "future") {
|
||||
// first 0, then 1
|
||||
|
|
@ -573,6 +602,17 @@ export default {
|
|||
("0" + monthNum).slice(-2) +
|
||||
"-" +
|
||||
("0" + i).slice(-2);
|
||||
const dayIndex = convertDateStringToDate(dateString).getDay();
|
||||
const dayObject = DAYS_OF_WEEK[dayIndex];
|
||||
const isSelectable =
|
||||
this.selectableDatesData.findIndex((date) => date.date === dateString) > -1
|
||||
? true
|
||||
: false;
|
||||
const isPricingByDayUpchargeDay = dayObject.isPricingByDayUpchargeDay;
|
||||
const displayPrice = isPricingByDayUpchargeDay
|
||||
? options.pricingByDayBasePrice + options.pricingByDayUpcharge
|
||||
: options.pricingByDayBasePrice;
|
||||
const priceString = "$" + displayPrice;
|
||||
|
||||
if (offset === 0 && i === this.todayDateNum) {
|
||||
dayClasses += " current-day";
|
||||
|
|
@ -583,8 +623,8 @@ export default {
|
|||
if (offset === 0 && i > this.todayDateNum && calendarViewDirection === "past") {
|
||||
dayClasses += " unavailable-day";
|
||||
}
|
||||
if (convertDateStringToDate(dateString).getDay() === 0) {
|
||||
dayClasses += " sunday";
|
||||
if (dayIndex === 0) {
|
||||
dayClasses += " " + dayObject.cssClass;
|
||||
}
|
||||
if (
|
||||
this.hideSomeDaysForInitialView &&
|
||||
|
|
@ -598,10 +638,9 @@ export default {
|
|||
dateNum: i,
|
||||
dayClasses: dayClasses,
|
||||
inputValue: dateString,
|
||||
isSelectable:
|
||||
this.selectableDatesData.findIndex((date) => date.date === dateString) > -1
|
||||
? true
|
||||
: false,
|
||||
priceString: priceString,
|
||||
isSelectable: isSelectable,
|
||||
isPricingByDayUpchargeDay: isPricingByDayUpchargeDay,
|
||||
};
|
||||
dates.push(dateObject);
|
||||
}
|
||||
|
|
@ -897,7 +936,6 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:checked {
|
||||
@include media-breakpoint-up(sm) {
|
||||
box-shadow: 0 0 0 4px transparent;
|
||||
|
|
@ -924,9 +962,7 @@ export default {
|
|||
|
||||
&.selectable-day {
|
||||
label {
|
||||
color: $blue;
|
||||
background-color: $blue-100;
|
||||
border: 1px solid $blue;
|
||||
min-width: 2.5rem;
|
||||
width: 2.5rem;
|
||||
border-radius: 50%;
|
||||
|
|
@ -934,12 +970,11 @@ export default {
|
|||
}
|
||||
&.unavailable-day {
|
||||
label {
|
||||
color: $gray-500;
|
||||
background-color: $gray-100;
|
||||
border: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
//NEEDED?
|
||||
&.unavailable-day:not(&.sunday) {
|
||||
label {
|
||||
&::before {
|
||||
|
|
@ -949,7 +984,6 @@ export default {
|
|||
left: -1rem;
|
||||
width: 1rem;
|
||||
height: 2.5rem;
|
||||
background: $gray-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1056,7 +1090,107 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
// pricing by day override styles
|
||||
&.pricing-by-day {
|
||||
.calendar-grid-container .grid-item {
|
||||
margin: 0 0 0.15rem 0;
|
||||
}
|
||||
.month-year {
|
||||
grid-area: 1 / 1 / 2 / 8;
|
||||
}
|
||||
.legend {
|
||||
display: none;
|
||||
}
|
||||
.radio-wrapper {
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
color: $black;
|
||||
|
||||
input[type="radio"] {
|
||||
&:focus-visible + label {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:focus + label,
|
||||
&:checked:focus + label {
|
||||
box-shadow: none;
|
||||
background-color: $white;
|
||||
color: $black;
|
||||
}
|
||||
&:checked + label {
|
||||
background: $blue-100;
|
||||
border: 2px solid $blue;
|
||||
border-radius: 0.25rem;
|
||||
color: $black;
|
||||
span {
|
||||
font-family: AvertaSemibold;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
label {
|
||||
flex-direction: column;
|
||||
height: 2.5rem;
|
||||
width: 100%;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.2;
|
||||
justify-content: center;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
&.selectable-day {
|
||||
label {
|
||||
color: $black;
|
||||
background-color: $blue-100;
|
||||
min-width: 2.5rem;
|
||||
width: 2.5rem;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
}
|
||||
&.current-day {
|
||||
label:after {
|
||||
margin-top: 0.2rem;
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.show-pricing-by-day {
|
||||
.radio-wrapper {
|
||||
&.selectable-day label span {
|
||||
text-decoration: none;
|
||||
color: $black;
|
||||
font-weight: 400;
|
||||
font-family: "AvertaSemibold";
|
||||
|
||||
&.price {
|
||||
font-family: "AvertaRegular";
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
&.upch-day label span.price {
|
||||
color: $gray-600;
|
||||
font-weight: 400;
|
||||
font-family: $font-family-sans-serif;
|
||||
}
|
||||
input[type="radio"] {
|
||||
&:focus + label,
|
||||
&:checked:focus + label {
|
||||
color: $gray-600;
|
||||
}
|
||||
&:checked + label {
|
||||
color: $blue;
|
||||
span {
|
||||
font-weight: 400;
|
||||
font-family: "AvertaSemibold";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
display: block;
|
||||
position: relative;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -11,6 +11,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="footer-inner-wrapper">
|
||||
<p class="mx-3 my-0 pb-1">© 2025 Safelite Group</p>
|
||||
<textLink
|
||||
linkType="newWindowLink"
|
||||
text="Terms of service"
|
||||
|
|
@ -32,11 +33,6 @@
|
|||
linkType="navigation"
|
||||
text="Cookie preferences"
|
||||
href="javascript:OneTrust.ToggleInfoDisplay();" />
|
||||
<textLink
|
||||
linkType="newWindowLink"
|
||||
text="Warranty"
|
||||
href="//www.safelite.com/national-lifetime-warranty"
|
||||
target="_blank" />
|
||||
<textLink
|
||||
linkType="newWindowLink"
|
||||
text="Notice at collection"
|
||||
|
|
@ -83,6 +79,14 @@ export default {
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
p {
|
||||
font-size: 0.875rem;
|
||||
color: $black;
|
||||
@include media-breakpoint-up(md) {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(a) {
|
||||
text-decoration: none;
|
||||
&.new-window-link {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,10 @@
|
|||
@back-clicked="backButtonAction"
|
||||
@ForwardClicked="forwardButtonAction" />
|
||||
|
||||
<textBlock cmsWidgetName="DisclaimerCopyWidget" typeStyle="caption" />
|
||||
<textBlock
|
||||
class="mb-5"
|
||||
cmsWidgetName="DisclaimerCopyWidget"
|
||||
typeStyle="caption" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -203,3 +203,9 @@ export default {
|
|||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-autocomplete {
|
||||
z-index: 3;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -275,8 +275,8 @@ export default {
|
|||
const emailFromStore = store.getters.order.customer.emailAddress;
|
||||
const isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
||||
const isPopupSkipped =
|
||||
store.getters.pageData(fmgPageValues.QUOTE).saveProgressPopupSkipped === true;
|
||||
const showSaveProgressPopup = isEmailInStoreOnPageLoad || isPopupSkipped ? false : true;
|
||||
store.getters.pageData(fmgPageValues.QUOTE)?.saveProgressPopupSkipped === true;
|
||||
const showSaveProgressPopup = !(isEmailInStoreOnPageLoad || isPopupSkipped);
|
||||
const showSaveProgressModal = isEmailInStoreOnPageLoad ? false : true;
|
||||
const shouldSkipToInsurance =
|
||||
getBoolFromString(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
marginTopSizeOverride="1" />
|
||||
</template>
|
||||
<locationAlerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" />
|
||||
<datePickerForPricingByDay
|
||||
<datePicker
|
||||
customComponentId="dateQuestion"
|
||||
selectableDatesSetting="custom"
|
||||
ref="datePicker"
|
||||
|
|
@ -77,7 +77,7 @@ import navbar from "@/fmg-components/nav-bar/nav-bar";
|
|||
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
||||
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import datePickerForPricingByDay from "@/experiment-components/date-picker-for-pricing-by-day";
|
||||
import datePicker from "@/digital-components/date-picker/date-picker";
|
||||
import locationAlerts from "@/layouts/schedule/location-alerts/location-alerts";
|
||||
import timeSlotModalQuestion from "./time-slot-modal-question/time-slot-modal-question";
|
||||
import textBlock from "@/digital-components/text-block/text-block";
|
||||
|
|
@ -298,14 +298,13 @@ export default {
|
|||
);
|
||||
|
||||
// While Pricing By Day Experiment is active, using the updated datePicker
|
||||
const datePickerInitialDataPromise =
|
||||
await datePickerForPricingByDay.methods.loadInitialData({
|
||||
// setup config options for date-picker
|
||||
selectableDatesSetting: "custom",
|
||||
initialViewRowsToShow: 5,
|
||||
customSelectableDatesCallback: getAvailableDates,
|
||||
preSelectedDate: preSelectedDate,
|
||||
});
|
||||
const datePickerInitialDataPromise = await datePicker.methods.loadInitialData({
|
||||
// setup config options for date-picker
|
||||
selectableDatesSetting: "custom",
|
||||
initialViewRowsToShow: 5,
|
||||
customSelectableDatesCallback: getAvailableDates,
|
||||
preSelectedDate: preSelectedDate,
|
||||
});
|
||||
|
||||
// Get pricingByDayUpcharge needed for Pricing By Day
|
||||
const pricingByDayUpchargePartPromise = showPricingByDay
|
||||
|
|
@ -735,7 +734,7 @@ export default {
|
|||
funnelSubHeader,
|
||||
Form,
|
||||
loadingModal,
|
||||
datePickerForPricingByDay,
|
||||
datePicker,
|
||||
locationAlerts,
|
||||
timeSlotModalQuestion,
|
||||
textBlock,
|
||||
|
|
|
|||
Loading…
Reference in a new issue