Merge branch 'develop' into feature/CSR-1109

This commit is contained in:
Leah Schumann 2023-05-23 07:05:20 -04:00
commit 01e570e70e
9 changed files with 115 additions and 80 deletions

View file

@ -52,7 +52,7 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
:isWide="isWide" :isWide="isWide"
:validationRules="validationRules" :validationRules="validationRules"
:textPosition="textPosition" :textPosition="textPosition"
:additionalButtonStyling="additionalButtonStyling" :additionalButtonData="additionalButtonData"
:lastValuePushedToGa="lastValuePushedToGa" :lastValuePushedToGa="lastValuePushedToGa"
:setLastValuePushedToGa="setLastValuePushedToGa" :setLastValuePushedToGa="setLastValuePushedToGa"
:suppressError="suppressError" :suppressError="suppressError"
@ -126,7 +126,7 @@ export default {
suppressError: Boolean, suppressError: Boolean,
useTextForValue: Boolean, useTextForValue: Boolean,
valueToLogType: String, valueToLogType: String,
additionalButtonStyling: String, additionalButtonData: Object,
isSmallQuestionText: Boolean, isSmallQuestionText: Boolean,
customButtonQuestionId: String, customButtonQuestionId: String,
logDisplayedValuesEvent: { logDisplayedValuesEvent: {

View file

@ -72,6 +72,7 @@
<script> <script>
// Supporting files // Supporting files
import loader from "@/ux-components/loader/loader"; import loader from "@/ux-components/loader/loader";
import store from "@/store";
import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from "./mixins/constants"; import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from "./mixins/constants";
import { selectableDaysOptions, requiredParameter, forceTwoDigitString } from "./mixins/helpers"; import { selectableDaysOptions, requiredParameter, forceTwoDigitString } from "./mixins/helpers";
@ -244,7 +245,8 @@ export default {
let myPromise = new Promise((resolve, reject) => { let myPromise = new Promise((resolve, reject) => {
const response = config.customSelectableDatesCallback( const response = config.customSelectableDatesCallback(
initialViewStartDate, initialViewStartDate,
initialViewEndDate initialViewEndDate,
store.getters.order.serviceLocation.appointmentType
); );
resolve(response); resolve(response);
}); });
@ -523,7 +525,8 @@ export default {
async updateSelectableDates(monthStart, monthEnd) { async updateSelectableDates(monthStart, monthEnd) {
const moreSelectableDates = await this.customSelectableDatesCallback( const moreSelectableDates = await this.customSelectableDatesCallback(
monthStart, monthStart,
monthEnd monthEnd,
this.$store.getters.order.serviceLocation.appointmentType
); );
moreSelectableDates.days.forEach((selectableDate) => { moreSelectableDates.days.forEach((selectableDate) => {
const index = this.selectableDatesData.findIndex( const index = this.selectableDatesData.findIndex(

View file

@ -5,7 +5,7 @@
:groupName="groupName" :groupName="groupName"
buttonTypeString="listButtonHorizontal" buttonTypeString="listButtonHorizontal"
v-model="selectedValues" v-model="selectedValues"
additionalButtonStyling="listButtonHorizontalStrong" :additionalButtonData="{ additionalButtonStyling: 'listButtonHorizontalStrong' }"
isRequired /> isRequired />
</div> </div>
</template> </template>

View file

@ -0,0 +1,53 @@
<template>
<alert
v-for="alert in prefixedAlertReasons"
:key="alert.cmsWidgetName"
:ref="alert.cmsWidgetName"
class="mt-2 mb-3"
:cmsWidgetName="alert.cmsWidgetName"
alertClass="alert-warning" />
</template>
<script>
import alert from "@/ux-components/alert/alert";
import { getAlertReasons } from "@/layouts/schedule/helpers/schedule-helper";
export default {
name: "locationAlerts",
data() {
return {
alertReasons: [],
};
},
props: {
cmsWidgetPrefix: {
type: String,
default: "",
},
},
computed: {
prefixedAlertReasons() {
return this.alertReasons.reduce((newObj, alert) => {
newObj.push({
cmsWidgetName: `${this.cmsWidgetPrefix}${alert}`,
alertReason: alert,
});
return newObj;
}, []);
},
},
methods: {
loadInitialData(zipCodeCtu) {
return getAlertReasons(zipCodeCtu);
},
initializeComponent(initialData) {
this.alertReasons = initialData;
},
cmsHeadlineTextFound(widgetName) {
return this.getCmsContent(widgetName, "HeadlineText") !== "";
},
},
components: {
alert,
},
};
</script>

View file

@ -18,17 +18,7 @@
<span v-else class="m-0 text-body" v-html="copy"></span> <span v-else class="m-0 text-body" v-html="copy"></span>
</span> </span>
</div> </div>
<template v-if="displayWeatherAlert"> <location-alerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" />
<alert
v-for="alert in weatherAlerts"
v-show="cmsHeadlineTextFound(alert.cmsWidgetName)"
:key="alert.cmsWidgetName"
:ref="alert.cmsWidgetName"
class="mt-2 mb-3"
:cmsWidgetName="alert.cmsWidgetName"
alertClass="alert-warning" />
</template>
<date-picker <date-picker
selectableDatesSetting="custom" selectableDatesSetting="custom"
ref="datePicker" ref="datePicker"
@ -62,13 +52,13 @@
<script> <script>
// Components // Components
import alert from "@/ux-components/alert/alert";
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import { Form, defineRule } from "vee-validate"; import { Form, defineRule } from "vee-validate";
import datePicker from "@/digital-components/date-picker/date-picker"; 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 timeSlotModalQuestion from "./time-slot-modal-question/time-slot-modal-question";
// Supporting files // Supporting files
@ -77,7 +67,6 @@ import baseMixin from "@/mixins/base-mixin.js";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper"; import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { getAlertReasons } from "@/layouts/schedule/helpers/schedule-helper";
import { import {
doesCopyContainRouterLink, doesCopyContainRouterLink,
splitCopyOnCMSPlaceHolder, splitCopyOnCMSPlaceHolder,
@ -91,14 +80,14 @@ import store from "@/store";
defineRule("date-required", required(errorMessages.DATE_REQUIRED)); defineRule("date-required", required(errorMessages.DATE_REQUIRED));
defineRule("time-slot-selection-required", required(errorMessages.DATE_REQUIRED)); defineRule("time-slot-selection-required", required(errorMessages.DATE_REQUIRED));
const getAvailableDates = async (startDate, endDate) => { const getAvailableDates = async (startDate, endDate, appointmentType) => {
// USING DATES PASSED, MAKE AN API CALL // USING DATES PASSED, MAKE AN API CALL
const newShopTimeSlotsResponse = await baseMixin.methods.dispatchStoreAction( const newShopTimeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
storeActions.GET_SHOP_TIME_SLOTS, storeActions.GET_SHOP_TIME_SLOTS,
{ {
startDate: startDate, startDate: startDate,
endDate: endDate, endDate: endDate,
shopAppointmentType: "mobile", // TODO - PASS THIS IN FROM PREVIOUS PAGE? shopAppointmentType: appointmentType,
}, },
false false
); );
@ -125,7 +114,6 @@ export default {
selectedDate: null, selectedDate: null,
selectedTimeSlotId: null, selectedTimeSlotId: null,
selectableDatesData: [], selectableDatesData: [],
weatherAlerts: [],
mobileEarlyBirdFee: null, mobileEarlyBirdFee: null,
}; };
}, },
@ -167,7 +155,9 @@ export default {
const earlyBirdPromise = baseMixin.methods.dispatchStoreAction( const earlyBirdPromise = baseMixin.methods.dispatchStoreAction(
storeActions.GET_MOBILE_EARLY_BIRD_FEE storeActions.GET_MOBILE_EARLY_BIRD_FEE
); );
const alertReasonsPromise = getAlertReasons(store.getters.order.serviceLocation.zipCodeCtu); const alertReasonsPromise = locationAlerts.methods.loadInitialData(
store.getters.order.serviceLocation.zipCodeCtu
);
// Settle promises and get results // Settle promises and get results
const promiseResultMap = [ const promiseResultMap = [
@ -198,8 +188,8 @@ export default {
// Call the "next" function to complete the transition to this page. // Call the "next" function to complete the transition to this page.
next((vm) => { next((vm) => {
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
vm.setData(resultMap.alertReasons);
vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData); vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
vm.selectableDatesData = resultMap.datePickerInitialData.initialShopTimeSlotsResponse; vm.selectableDatesData = resultMap.datePickerInitialData.initialShopTimeSlotsResponse;
if (resultMap.earlyBird) { if (resultMap.earlyBird) {
vm.mobileEarlyBirdFee = resultMap.pricingResults[0]; vm.mobileEarlyBirdFee = resultMap.pricingResults[0];
@ -214,9 +204,6 @@ 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 // 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); return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
}, },
displayWeatherAlert() {
return this.weatherAlerts.length > 0;
},
appointmentType() { appointmentType() {
return this.$store.getters.order.serviceLocation.appointmentType; return this.$store.getters.order.serviceLocation.appointmentType;
}, },
@ -257,41 +244,17 @@ export default {
// NEED TODO - WHAT ARE PAGE REQ'S FOR THIS PAGE? // NEED TODO - WHAT ARE PAGE REQ'S FOR THIS PAGE?
}, },
async getAvailableDatesMethod(startDate, endDate) { async getAvailableDatesMethod(startDate, endDate) {
const newShopTimeSlots = await getAvailableDates(startDate, endDate); const newShopTimeSlots = await getAvailableDates(
startDate,
endDate,
this.appointmentType
);
// ADD API CALL RESULTS TO EXISTING DATE DATA // ADD API CALL RESULTS TO EXISTING DATE DATA
this.selectableDatesData.days = this.selectableDatesData.days.concat( this.selectableDatesData.days = this.selectableDatesData.days.concat(
newShopTimeSlots.days newShopTimeSlots.days
); );
return newShopTimeSlots; return newShopTimeSlots;
}, },
setData(alertReasonsData) {
if (alertReasonsData) {
this.convertReasonsToCmsAlerts(alertReasonsData);
}
},
cmsHeadlineTextFound(widgetName) {
return this.getCmsContent(widgetName, "HeadlineText") !== "";
},
convertReasonsToCmsAlerts(data) {
this.weatherAlerts = data.reduce((newObj, alert) => {
newObj.push({
cmsWidgetName: `LocationAlert-${alert}`,
alertReason: alert,
});
return newObj;
}, []);
},
async getWeatherAlertReasons(ctu) {
await getAlertReasons(ctu)
.then((response) => {
if (response.data) {
this.convertReasonsToCmsAlerts(response.data);
}
})
.catch(() => {
console.log("error fetching alert reasons..");
});
},
getServiceZipCtuCodeFromStore() { getServiceZipCtuCodeFromStore() {
return store.getters.order.serviceLocation.zipCodeCtu; return store.getters.order.serviceLocation.zipCodeCtu;
}, },
@ -338,15 +301,14 @@ export default {
}, },
}, },
components: { components: {
alert,
funnelHeader, funnelHeader,
funnelFooter, funnelFooter,
funnelSubHeader, funnelSubHeader,
Form, Form,
loadingModal, loadingModal,
datePicker, datePicker,
locationAlerts,
timeSlotModalQuestion, timeSlotModalQuestion,
}, },
mounted() {},
}; };
</script> </script>

View file

@ -8,8 +8,8 @@
:onModalClosedCallback="onModalClosed" :onModalClosedCallback="onModalClosed"
@footer-button-event="closeModal"> @footer-button-event="closeModal">
<textBlock <textBlock
v-show="inshopAppointmentDurationTextWithTime" v-show="durationTextBlockCopy"
:customText="inshopAppointmentDurationTextWithTime" :customText="durationTextBlockCopy"
justifyText="center" justifyText="center"
typeStyle="small" typeStyle="small"
class="duration-text-block" /> class="duration-text-block" />
@ -90,13 +90,18 @@ export default {
watch: { watch: {
modelValue() { modelValue() {
this.selectedTimeSlot = this.modelValue; this.selectedTimeSlot = this.modelValue;
// Run component validation that is used at parent level
this.handleChange(this.modelValue); this.handleChange(this.modelValue);
}, },
// dateAndTimeSlotData(newValue, oldValue) {
// const numberOfOptions = newValue?.timeSlots.length;
// console.log('running');
// if (numberOfOptions === 1) {
// this.selectedTimeSlot = newValue.timeSlots[0].id;
// }
// }
}, },
computed: { computed: {
appointmentDurationTextFromCms() {
return this.getCmsContent(this.cmsWidgetName, "SubheaderText");
},
supplementalInformationBlock() { supplementalInformationBlock() {
let appointmentTypeCmsWidgetName; let appointmentTypeCmsWidgetName;
let cmsFieldName = "BodyText"; let cmsFieldName = "BodyText";
@ -127,6 +132,29 @@ export default {
dropoffDisclaimerText() { dropoffDisclaimerText() {
return this.getCmsContent(this.dropoffCmsWidgetName, "FooterText"); return this.getCmsContent(this.dropoffCmsWidgetName, "FooterText");
}, },
dropOffDurationText() {
return this.getCmsContent(this.dropoffCmsWidgetName, "SubheaderText");
},
inshopDurationText() {
const inshopDurationTextWithoutTime = this.getCmsContent(
this.cmsWidgetName,
"SubheaderText"
);
const inshopDurationTime = this.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 {
return this.dropOffDurationText;
}
},
shouldShowDropoffDisclaimerText() { shouldShowDropoffDisclaimerText() {
return this.appointmentType === AppointmentTypeStrings.DROP_OFF && !this.isSameDay; return this.appointmentType === AppointmentTypeStrings.DROP_OFF && !this.isSameDay;
}, },
@ -145,21 +173,6 @@ export default {
// Ex. Tuesday, April 23 // Ex. Tuesday, April 23
return `${weekdayName}, ${month} ${numberDayOfMonth}`; return `${weekdayName}, ${month} ${numberDayOfMonth}`;
}, },
inshopAppointmentDurationTextWithTime() {
if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
return null;
}
let durationSubHeaderText = this.appointmentDurationTextFromCms + " ";
if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
durationSubHeaderText += "All day";
} else {
durationSubHeaderText += this.getDisplayTextForDurationLength(
this.estimatedServiceMinutesMinimum,
this.estimatedServiceMinutesMaximum
);
}
return durationSubHeaderText;
},
availableTimeSlots() { availableTimeSlots() {
if (this.dateAndTimeSlotData === null) { if (this.dateAndTimeSlotData === null) {
return null; return null;

View file

@ -21,7 +21,7 @@ export default {
textPosition: String, textPosition: String,
screenReaderOnlyText: String, screenReaderOnlyText: String,
isWide: Boolean, isWide: Boolean,
additionalButtonStyling: String, additionalButtonData: Object,
}, },
computed: { computed: {
selectedValue: { selectedValue: {

View file

@ -57,7 +57,9 @@ describe("list-button-horizontal.vue", () => {
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
mockData: { mockData: {
propsData: { propsData: {
additionalButtonStyling: "listButtonHorizontalStrong", additionalButtonData: {
additionalButtonStyling: "listButtonHorizontalStrong",
},
}, },
}, },
}); });

View file

@ -30,7 +30,9 @@ export default {
mixins: [inputButtonWrapperMixin], mixins: [inputButtonWrapperMixin],
computed: { computed: {
isStrongStyling() { isStrongStyling() {
return this.additionalButtonStyling === "listButtonHorizontalStrong"; return (
this.additionalButtonData?.additionalButtonStyling === "listButtonHorizontalStrong"
);
}, },
}, },
components: { components: {