Move duration outside of date-picker into own component

This commit is contained in:
Scott Kiener 2025-07-31 09:48:43 -04:00
parent a193cd1808
commit 866eaf0e7b
3 changed files with 143 additions and 92 deletions

View file

@ -218,9 +218,6 @@ export default {
pricingByDayBasePrice: Number,
pricingByDayUpcharge: Number,
isPricingByDayExperiment: Boolean,
appointmentType: String,
estimatedServiceMinutesMinimum: Number,
estimatedServiceMinutesMaximum: Number,
isMobileSelected: Boolean,
},
setup(props) {

View file

@ -0,0 +1,126 @@
<template>
<textBlock
v-show="durationTextBlockCopy"
:customText="durationTextBlockCopy"
justifyText="center"
typeStyle="small"
marginTopSizeOverride="0"
class="duration-text-block" />
</template>
<script>
// Components
import textBlock from "@/digital-components/text-block/text-block";
// Constants
import {
AppointmentTypeStrings,
RouteCodeFlags,
cmsWidgetFieldMappings
} from "@/constants/schedule-constants";
// Helpers
import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helper";
export default {
name: "duration-text-block",
props: {
isSameDay: Boolean,
appointmentType: String,
estimatedServiceMinutesMinimum: String,
estimatedServiceMinutesMaximum: String,
isOvernightDropoff: Boolean,
},
data() {
return {
selectedRouteCode: null,
selectedAnswerForDropOffOrInshop: null,
selectedAnswerForTimeSlots: null,
};
},
computed: {
dropOffDurationText() {
return this.getCmsContent("DropOffTimeSlotModal", cmsWidgetFieldMappings.DURATION);
},
sameDayDropoffDurationText() {
return this.getCmsContent(
"SameDayDropOffTimeSlotModal",
cmsWidgetFieldMappings.DURATION
);
},
overnightDropoffDurationText() {
return this.getCmsContent(
"OvernightDropOffTimeSlotModal",
cmsWidgetFieldMappings.DURATION
);
},
inshopDurationText() {
const inshopDurationTextWithoutTime = this.getCmsContent(
"TimeSlotModalQuestion",
cmsWidgetFieldMappings.DURATION
);
const inshopDurationTime = getDisplayTextForDurationLength(
this.estimatedServiceMinutesMinimum,
this.estimatedServiceMinutesMaximum
);
if (this.estimatedServiceMinutesMinimum && this.estimatedServiceMinutesMaximum) {
return `${inshopDurationTextWithoutTime} ${inshopDurationTime}`;
}
return null;
},
mobileDurationText() {
const mobileDurationTextWithoutTime = this.getCmsContent(
"TimeSlotModalQuestion",
cmsWidgetFieldMappings.DURATION
);
const mobileDurationTime = getDisplayTextForDurationLength(
this.estimatedServiceMinutesMinimum,
this.estimatedServiceMinutesMaximum
);
if (this.estimatedServiceMinutesMinimum && this.estimatedServiceMinutesMaximum) {
return `${mobileDurationTextWithoutTime} ${mobileDurationTime}`;
}
return null;
},
durationTextBlockCopy() {
console.log("durationTextBlockCopy", this.appointmentType, this.estimatedServiceMinutesMaximum, this.estimatedServiceMinutesMinimum);
if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
return this.mobileDurationText;
} else if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
return this.inshopDurationText;
} else if (
this.appointmentType === AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF ||
this.appointmentType === AppointmentTypeStrings.DROP_OFF
) {
return this.getDurationTextBlockCopyForDropoff();
}
return null;
},
},
methods: {
getDurationTextBlockCopyForDropoff() {
if (this.isOvernightDropoff) {
return this.overnightDropoffDurationText;
} else {
if (this.isSameDay) {
return this.sameDayDropoffDurationText;
} else {
return this.dropOffDurationText;
}
}
},
},
components: {
textBlock,
}
}
</script>
<style>
</style>

View file

@ -118,13 +118,14 @@
<locationAlerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" />
<div class="date-picker-header">
<funnelSubHeader cmsWidgetName="DatePickerSubHeaderWidget" class="mt-5" />
<textBlock
v-show="durationTextBlockCopy"
:customText="durationTextBlockCopy"
justifyText="center"
typeStyle="small"
marginTopSizeOverride="0"
class="duration-text-block" />
<durationTextBlock
:isSameDay="isSameDay"
:appointmentType="appointmentType"
:estimatedServiceMinutesMinimum="estimatedServiceMinutesMinimum"
:estimatedServiceMinutesMaximum="estimatedServiceMinutesMaximum"
:isOvernightDropoff="isOvernightDropoff"
/>
</div>
<datePicker
:currentZip="zipCode"
@ -142,10 +143,7 @@
:pricingByDayBasePrice="pricingByDayBasePrice"
:pricingByDayUpcharge="pricingByDayUpcharge"
:showPricingByDay="showPricingByDay"
:isPricingByDayExperiment="isPricingByDayExperiment"
:appointmentType="appointmentType"
:estimatedServiceMinutesMinimum="getServiceMinutesMin"
:estimatedServiceMinutesMaximum="getServiceMinutesMax" />
:isPricingByDayExperiment="isPricingByDayExperiment" />
<timeSlotQuestion
ref="timeSlotModalQuestion"
@timeSlotSelected="updateTimeSlot"
@ -187,6 +185,7 @@ import shopQuestionPopup from "@/layouts/service-location/shop-question/shop-que
import buttonQuestion from "@/digital-components/button-question/button-question.vue";
import shopListButton from "@/layouts/service-location/shop-question/shop-list-button/shop-list-button";
import timeSlotQuestion from "@/layouts/schedule/time-slot-question/time-slot-question.vue";
import durationTextBlock from "@/layouts/schedule/duration-text-block/duration-text-block.vue";
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar";
@ -208,7 +207,6 @@ import {
RouteCodeFlags,
PREMIUM_FEE_PART_TYPE,
PRICING_BY_DAY_PART_TYPE,
cmsWidgetFieldMappings
} from "@/constants/schedule-constants";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
@ -241,7 +239,6 @@ import { getAmountDue, getPricingByDayPartWithPrice } from "@/helpers/pricing-he
import { getItemsWithoutRecalParts } from "@/helpers/recal-helper";
import { deepClone } from "@/helpers/object-helper";
import { debugLog } from "@/helpers/debug-log-helper";
import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helper";
// DEFINE VALIDATION RULES
defineRule("mobile-location-required", (value) => {
@ -822,12 +819,12 @@ export default {
// Splits content when brackets are found in text so that text can be looped through and router-link can be injected when needed
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
},
getServiceMinutesMin() {
estimatedServiceMinutesMinimum() {
return this.isMobileSelected
? this.selectableDatesMobile.estimatedServiceMinutesMinimum
: this.selectableDatesInshop.estimatedServiceMinutesMinimum;
},
getServiceMinutesMax() {
estimatedServiceMinutesMaximum() {
return this.isMobileSelected
? this.selectableDatesMobile.estimatedServiceMinutesMaximum
: this.selectableDatesInshop.estimatedServiceMinutesMaximum;
@ -847,88 +844,18 @@ export default {
);
}
},
durationTextBlockCopy() {
console.log("durationTextBlockCopy", this.appointmentType, this.getServiceMinutesMax, this.getServiceMinutesMin);
if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
return this.mobileDurationText;
} else if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
return this.inshopDurationText;
} else if (
this.appointmentType === AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF ||
this.appointmentType === AppointmentTypeStrings.DROP_OFF
) {
return this.getDurationTextBlockCopyForInshopOrDropoff(this.selectedTimeSlotInfo.timeSlot.routeCode);
}
return null;
},
isSameDay() {
const todaysDate = new Date().toISOString().split("T")[0];
return this.selectedDate === todaysDate;
},
dropOffDurationText() {
return this.getCmsContent("DropOffTimeSlotModal", cmsWidgetFieldMappings.DURATION);
},
sameDayDropoffDurationText() {
return this.getCmsContent(
"SameDayDropOffTimeSlotModal",
cmsWidgetFieldMappings.DURATION
isOvernightDropoff() {
return (
this.selectedTimeSlotInfo?.timeSlot?.routeCode && this.selectedTimeSlotInfo.timeSlot.routeCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)
);
},
overnightDropoffDurationText() {
return this.getCmsContent(
"OvernightDropOffTimeSlotModal",
cmsWidgetFieldMappings.DURATION
);
},
inshopDurationText() {
const inshopDurationTextWithoutTime = this.getCmsContent(
"TimeSlotModalQuestion",
cmsWidgetFieldMappings.DURATION
);
const inshopDurationTime = getDisplayTextForDurationLength(
this.getServiceMinutesMin,
this.getServiceMinutesMax
);
if (this.getServiceMinutesMin && this.getServiceMinutesMax) {
return `${inshopDurationTextWithoutTime} ${inshopDurationTime}`;
}
return null;
},
mobileDurationText() {
const mobileDurationTextWithoutTime = this.getCmsContent(
"TimeSlotModalQuestion",
cmsWidgetFieldMappings.DURATION
);
const mobileDurationTime = getDisplayTextForDurationLength(
this.getServiceMinutesMin,
this.getServiceMinutesMax
);
if (this.getServiceMinutesMin && this.getServiceMinutesMax) {
return `${mobileDurationTextWithoutTime} ${mobileDurationTime}`;
}
return null;
},
}
},
methods: {
splitCopyOnCMSPlaceHolder,
getDurationTextBlockCopyForInshopOrDropoff(selectedRouteCode) {
if (selectedRouteCode?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
return this.overnightDropoffDurationText;
} else if (selectedRouteCode?.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
if (this.isSameDay) {
return this.sameDayDropoffDurationText;
} else {
return this.dropOffDurationText;
}
}
return this.inshopDurationText;
},
arePagePrerequisitesValid() {
const paymentInfo = store.getters.payment.isInsurance !== null;
const damageInfo =
@ -1851,6 +1778,7 @@ export default {
contentGroupModal,
shopQuestionPopup,
buttonQuestion,
durationTextBlock
},
};
</script>