CASH-845: move duration text block from time-slot-question to date-picker

This commit is contained in:
AdamCaouetteSafelite 2025-07-10 14:34:44 -04:00
parent 749c5cc466
commit 995c2da5a1
4 changed files with 94 additions and 66 deletions

View file

@ -16,10 +16,19 @@ const RouteCodeFlags = {
OVERNIGHT_DROP_OFF: "OVERNIGHT DROP OFF", OVERNIGHT_DROP_OFF: "OVERNIGHT DROP OFF",
}; };
const cmsWidgetFieldMappings = {
MODAL_CLOSE_BUTTON: "FooterText",
SUPPLEMENTAL_INFORMATION: "BodyText",
TIME_SLOT_BUTTON: "HeaderText",
DISCLAIMER: "FooterText",
DURATION: "SubheaderText",
};
export { export {
AppointmentTypeStrings, AppointmentTypeStrings,
PREMIUM_TIME_SLOT_ID_FLAG, PREMIUM_TIME_SLOT_ID_FLAG,
PREMIUM_FEE_PART_TYPE, PREMIUM_FEE_PART_TYPE,
PRICING_BY_DAY_PART_TYPE, PRICING_BY_DAY_PART_TYPE,
RouteCodeFlags, RouteCodeFlags,
cmsWidgetFieldMappings,
}; };

View file

@ -142,7 +142,7 @@
overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal" overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal"
dropOffOrPickATimeQuestionCmsWidgetName="DropOffOrPickATimeQuestionWidget" dropOffOrPickATimeQuestionCmsWidgetName="DropOffOrPickATimeQuestionWidget"
:selectedDate="selectedDate" :selectedDate="selectedDate"
:appointmentType="appointmentTypeForTimeSlotQuestion" :appointmentType="appointmentType"
:premiumAppointmentFee="premiumAppointmentFee" :premiumAppointmentFee="premiumAppointmentFee"
:displayWaitList="displayWaitList" :displayWaitList="displayWaitList"
:timeSlotsForSelectedDate="timeSlotsForSelectedDate" :timeSlotsForSelectedDate="timeSlotsForSelectedDate"
@ -156,6 +156,7 @@
<script> <script>
import timeSlotQuestion from "@/layouts/schedule/time-slot-question/time-slot-question.vue"; import timeSlotQuestion from "@/layouts/schedule/time-slot-question/time-slot-question.vue";
import textBlock from "@/digital-components/text-block/text-block";
// Supporting files // Supporting files
import loader from "@/ux-components/loader/loader"; import loader from "@/ux-components/loader/loader";
@ -166,7 +167,12 @@ import {
MONTHS_OF_YEAR, MONTHS_OF_YEAR,
DAYS_OF_WEEK, DAYS_OF_WEEK,
} from "@/digital-components/date-picker/mixins/constants"; } from "@/digital-components/date-picker/mixins/constants";
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants"; import {
AppointmentTypeStrings,
RouteCodeFlags,
PREMIUM_FEE_PART_TYPE,
cmsWidgetFieldMappings,
} from "@/constants/schedule-constants";
import { import {
selectableDaysOptions, selectableDaysOptions,
requiredParameter, requiredParameter,
@ -178,6 +184,7 @@ import {
import { useField, ErrorMessage } from "vee-validate"; import { useField, ErrorMessage } from "vee-validate";
import { deepClone } from "@/helpers/object-helper"; import { deepClone } from "@/helpers/object-helper";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helper";
export default { export default {
name: "datePicker", name: "datePicker",
@ -190,6 +197,7 @@ export default {
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(), selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
selectableDatesInshop: [], // NOTE: this and the mobile version below use monthNum (1-based), NOT monthIndex (0-based) selectableDatesInshop: [], // NOTE: this and the mobile version below use monthNum (1-based), NOT monthIndex (0-based)
selectableDatesMobile: [], selectableDatesMobile: [],
durationTextBlockCopyForInshopOrDropoff: null,
}; };
}, },
props: { props: {
@ -224,7 +232,7 @@ export default {
pricingByDayUpcharge: Number, pricingByDayUpcharge: Number,
isPricingByDayExperiment: Boolean, isPricingByDayExperiment: Boolean,
timeSlotsForSelectedDate: Object, timeSlotsForSelectedDate: Object,
appointmentTypeForTimeSlotQuestion: String, appointmentType: String,
premiumAppointmentFee: Object, premiumAppointmentFee: Object,
estimatedServiceMinutesMinimum: Number, estimatedServiceMinutesMinimum: Number,
estimatedServiceMinutesMaximum: Number, estimatedServiceMinutesMaximum: Number,
@ -289,6 +297,54 @@ export default {
this.$emit("update:modelValue", newSelectedDate); this.$emit("update:modelValue", newSelectedDate);
}, },
}, },
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
);
return `${inshopDurationTextWithoutTime} ${inshopDurationTime}`;
},
durationTextBlockCopy() {
if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
return null;
} 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.durationTextBlockCopyForInshopOrDropoff ?? this.inshopDurationText;
}
return null;
},
isSameDay() {
if (!this.timeSlotsForSelectedDate) {
return false;
}
const todaysDate = new Date().toISOString().split("T")[0];
return this.selectedDate === todaysDate;
},
}, },
methods: { methods: {
initializeComponent(initialData) { initializeComponent(initialData) {
@ -877,6 +933,18 @@ export default {
handleWaitListRequested(value) { handleWaitListRequested(value) {
this.$emit("waitListRequested", value); this.$emit("waitListRequested", value);
}, },
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;
},
}, },
watch: { watch: {
modelValue(newValue) { modelValue(newValue) {
@ -891,13 +959,17 @@ export default {
} }
}, },
selectedTimeSlotInfo(newValue) { selectedTimeSlotInfo(newValue) {
this.$emit("TimeSlotSelected", newValue); // NEEDED ON SCHEDULE - to update footer button text and to save to Store correctly const routeCode = newValue?.timeSlot?.routeCode;
this.durationTextBlockCopyForInshopOrDropoff =
this.getDurationTextBlockCopyForInshopOrDropoff(routeCode);
this.$emit("TimeSlotSelected", newValue); // needed to update footer button text on Schedule page and to save to Store correctly
}, },
}, },
components: { components: {
loader, loader,
ErrorMessage, ErrorMessage,
timeSlotQuestion, timeSlotQuestion,
textBlock,
}, },
}; };
</script> </script>

View file

@ -146,7 +146,7 @@
:showPricingByDay="showPricingByDay" :showPricingByDay="showPricingByDay"
:isPricingByDayExperiment="isPricingByDayExperiment" :isPricingByDayExperiment="isPricingByDayExperiment"
:timeSlotsForSelectedDate="timeSlotsForSelectedDate" :timeSlotsForSelectedDate="timeSlotsForSelectedDate"
:appointmentTypeForTimeSlotQuestion="appointmentType" :appointmentType="appointmentType"
:premiumAppointmentFee="mobilePremiumAppointmentFee" :premiumAppointmentFee="mobilePremiumAppointmentFee"
:estimatedServiceMinutesMinimum="getServiceMinutesMin" :estimatedServiceMinutesMinimum="getServiceMinutesMin"
:estimatedServiceMinutesMaximum="getServiceMinutesMax" :estimatedServiceMinutesMaximum="getServiceMinutesMax"
@ -1703,7 +1703,7 @@ export default {
.change-location a { .change-location a {
font-family: UrbanistSemibold; font-family: UrbanistSemibold;
} }
.date-picker-wrapper { .date-picker {
border-top: 1px solid $gray-500; border-top: 1px solid $gray-500;
margin-top: 1.5rem; margin-top: 1.5rem;
} }

View file

@ -1,11 +1,5 @@
<template> <template>
<div class="time-slots-question"> <div class="time-slots-question">
<textBlock
v-show="durationTextBlockCopy"
:customText="durationTextBlockCopy"
justifyText="center"
typeStyle="small"
class="duration-text-block" />
<buttonQuestion <buttonQuestion
v-if="isDropOffAppointmentAvailable" v-if="isDropOffAppointmentAvailable"
v-model="selectedAnswerForDropOffOrInshop" v-model="selectedAnswerForDropOffOrInshop"
@ -103,16 +97,9 @@ import {
RouteCodeFlags, RouteCodeFlags,
PREMIUM_TIME_SLOT_ID_FLAG, PREMIUM_TIME_SLOT_ID_FLAG,
PREMIUM_FEE_PART_TYPE, PREMIUM_FEE_PART_TYPE,
cmsWidgetFieldMappings,
} from "@/constants/schedule-constants"; } from "@/constants/schedule-constants";
const cmsWidgetFieldMappings = {
MODAL_CLOSE_BUTTON: "FooterText",
SUPPLEMENTAL_INFORMATION: "BodyText",
TIME_SLOT_BUTTON: "HeaderText",
DISCLAIMER: "FooterText",
DURATION: "SubheaderText",
};
const PICK_A_TIME_BUTTON_VALUE = "pick-a-time-selected"; const PICK_A_TIME_BUTTON_VALUE = "pick-a-time-selected";
defineRule("time-slot-required", required(errorMessages.OPTION_REQUIRED)); defineRule("time-slot-required", required(errorMessages.OPTION_REQUIRED));
@ -194,7 +181,11 @@ export default {
supplementalInformationBlock() { supplementalInformationBlock() {
let appointmentTypeCmsWidgetName; let appointmentTypeCmsWidgetName;
if (this.appointmentType === AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF) { if (
this.appointmentType === AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF ||
this.appointmentType === AppointmentTypeStrings.IN_SHOP ||
this.appointmentType === AppointmentTypeStrings.DROP_OFF
) {
return null; return null;
// This is planned to be used again for drop-off // This is planned to be used again for drop-off
// Wrote this to be ready for that eventuality, is untested and no HTML work done yet // Wrote this to be ready for that eventuality, is untested and no HTML work done yet
@ -286,51 +277,6 @@ export default {
// return null; // return null;
// } // }
// }, // },
dropOffDurationText() {
return this.getCmsContent(this.dropoffCmsWidgetName, cmsWidgetFieldMappings.DURATION);
},
sameDayDropoffDurationText() {
return this.getCmsContent(
this.sameDayDropOffCmsWidgetName,
cmsWidgetFieldMappings.DURATION
);
},
overnightDropoffDurationText() {
return this.getCmsContent(
this.overnightDropOffCmsWidgetName,
cmsWidgetFieldMappings.DURATION
);
},
inshopDurationText() {
const inshopDurationTextWithoutTime = this.getCmsContent(
this.cmsWidgetName,
cmsWidgetFieldMappings.DURATION
);
const inshopDurationTime = getDisplayTextForDurationLength(
this.estimatedServiceMinutesMinimum,
this.estimatedServiceMinutesMaximum
);
return `${inshopDurationTextWithoutTime} ${inshopDurationTime}`;
},
durationTextBlockCopy() {
if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
return null;
} else if (this.appointmentType === AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF) {
if (this.selectedRouteCode?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
return this.overnightDropoffDurationText;
} else if (this.selectedRouteCode?.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
if (this.isSameDay) {
return this.sameDayDropoffDurationText;
} else {
return this.dropOffDurationText;
}
}
return this.inshopDurationText;
}
return null;
},
isSameDay() { isSameDay() {
if (!this.timeSlotsForSelectedDate) { if (!this.timeSlotsForSelectedDate) {
return false; return false;
@ -609,6 +555,7 @@ export default {
selectedAnswerForDropOffOrInshop(newValue) { selectedAnswerForDropOffOrInshop(newValue) {
if (newValue == PICK_A_TIME_BUTTON_VALUE) { if (newValue == PICK_A_TIME_BUTTON_VALUE) {
this.selectedRouteCode = null; this.selectedRouteCode = null;
this.setSelectedTimeSlot();
} else { } else {
this.selectedAnswerForTimeSlots = null; this.selectedAnswerForTimeSlots = null;
this.selectedRouteCode = newValue; this.selectedRouteCode = newValue;