Refactored shop-list-button to no longer need so many props

Everyone single usage did the same thing, reduced boilerplate by moving it to the component itself
This commit is contained in:
Scott Kiener 2025-07-16 10:24:23 -04:00
parent 141ebc33f5
commit c1f7f7f734
6 changed files with 44 additions and 104 deletions

View file

@ -166,7 +166,6 @@ import shopQuestion from "@/layouts/service-location/shop-question/shop-question
import shopQuestionPopup from "@/layouts/service-location/shop-question/shop-question-popup"; import shopQuestionPopup from "@/layouts/service-location/shop-question/shop-question-popup";
import buttonQuestion from "@/digital-components/button-question/button-question.vue"; 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 shopListButton from "@/layouts/service-location/shop-question/shop-list-button/shop-list-button";
import { getAvailabilityRating } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar"; import navbar from "@/fmg-components/nav-bar/nav-bar";
@ -805,17 +804,7 @@ export default {
return this.displayNoShopsAlert || !this.isMobileAddressValid; return this.displayNoShopsAlert || !this.isMobileAddressValid;
}, },
additionalButtonData() { additionalButtonData() {
const startDate = new Date();
const endDate = new Date();
endDate.setDate(startDate.getDate() + 6);
const formattedStartDate = startDate.toISOString().split("T")[0];
const formattedEndDate = endDate.toISOString().split("T")[0];
return { return {
availabilityRatingCallback: getAvailabilityRating,
startDate: formattedStartDate,
endDate: formattedEndDate,
shopAppointmentType: this.appointmentType, shopAppointmentType: this.appointmentType,
}; };
}, },

View file

@ -122,35 +122,6 @@ export async function getShopProviderData(serviceZipCode) {
); );
} }
export async function getAvailabilityRating(
startDate,
endDate,
shopAppointmentType,
providerNumber
) {
// For a given shop provider number and date range, get the appointment time slots available
const shopTimeSlots = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_SHOP_TIME_SLOTS,
{
providerNumber: providerNumber,
startDate: startDate,
endDate: endDate,
shopAppointmentType: shopAppointmentType,
},
"service-location",
false
);
const numberOfDaysToEvaluate = 2;
const isGoodAvailability =
shopTimeSlots.data.days.filter((x) => x.timeSlots.length > 0).length >=
numberOfDaysToEvaluate;
const shopStatus = isGoodAvailability ? "high" : "low";
return shopStatus;
}
export async function getClosestApplicableShops(serviceZipCode, carId, pageNameToLog) { export async function getClosestApplicableShops(serviceZipCode, carId, pageNameToLog) {
if (!serviceZipCode) { if (!serviceZipCode) {
return null; return null;

View file

@ -148,11 +148,9 @@
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
import serviceZipModalQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-modal-question"; import serviceZipModalQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-modal-question";
import appointmentTypeQuestion from "@/layouts/service-location/appointment-type-question/appointment-type-question"; import appointmentTypeQuestion from "@/layouts/service-location/appointment-type-question/appointment-type-question";
import shopQuestion from "@/layouts/service-location/shop-question/shop-question";
import shopQuestionPopup from "@/layouts/service-location/shop-question/shop-question-popup"; import shopQuestionPopup from "@/layouts/service-location/shop-question/shop-question-popup";
import buttonQuestion from "@/digital-components/button-question/button-question.vue"; 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 shopListButton from "@/layouts/service-location/shop-question/shop-list-button/shop-list-button";
import { getAvailabilityRating } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar"; import navbar from "@/fmg-components/nav-bar/nav-bar";
@ -163,7 +161,6 @@ import contentGroupModal from "@/fmg-components/content-group-modal/content-grou
import textBlock from "@/digital-components/text-block/text-block"; import textBlock from "@/digital-components/text-block/text-block";
// Supporting files // Supporting files
import baseMixin from "@/mixins/base-mixin.js";
import experimentMixin from "@/mixins/experiment-mixin.js"; import experimentMixin from "@/mixins/experiment-mixin.js";
import { experimentSettings } from "@/constants/experiments"; import { experimentSettings } from "@/constants/experiments";
import { AppointmentTypeStrings } from "@/constants/schedule-constants"; import { AppointmentTypeStrings } from "@/constants/schedule-constants";
@ -450,17 +447,7 @@ export default {
return this.displayNoShopsAlert || !this.isMobileAddressValid; return this.displayNoShopsAlert || !this.isMobileAddressValid;
}, },
additionalButtonData() { additionalButtonData() {
const startDate = new Date();
const endDate = new Date();
endDate.setDate(startDate.getDate() + 6);
const formattedStartDate = startDate.toISOString().split("T")[0];
const formattedEndDate = endDate.toISOString().split("T")[0];
return { return {
availabilityRatingCallback: getAvailabilityRating,
startDate: formattedStartDate,
endDate: formattedEndDate,
shopAppointmentType: this.selectedAppointmentType, shopAppointmentType: this.selectedAppointmentType,
}; };
}, },

View file

@ -58,12 +58,15 @@ export default {
beforeMount() { beforeMount() {
if (this.displayAvailabilityIndicators) { if (this.displayAvailabilityIndicators) {
this.displayLoader(); this.displayLoader();
const startDate = this.additionalButtonData.startDate; const startDate = new Date();
const endDate = this.additionalButtonData.endDate; const endDate = new Date();
endDate.setDate(startDate.getDate() + 6);
const formattedStartDate = startDate.toISOString().split("T")[0];
const formattedEndDate = endDate.toISOString().split("T")[0];
const shopAppointmentType = this.additionalButtonData.shopAppointmentType; const shopAppointmentType = this.additionalButtonData.shopAppointmentType;
this.additionalButtonData this.getAvailabilityRating(formattedStartDate, formattedEndDate, shopAppointmentType, this.value)
.availabilityRatingCallback(startDate, endDate, shopAppointmentType, this.value)
.then((data) => { .then((data) => {
this.availabilityRating = data; this.availabilityRating = data;
}); });
@ -103,6 +106,34 @@ export default {
displayLoader() { displayLoader() {
this.isLoaderDisplayed = true; this.isLoaderDisplayed = true;
}, },
async getAvailabilityRating(
startDate,
endDate,
shopAppointmentType,
providerNumber
) {
// For a given shop provider number and date range, get the appointment time slots available
const shopTimeSlots = await this.dispatchStoreActionWithLogging(
this.storeActions.GET_SHOP_TIME_SLOTS,
{
providerNumber: providerNumber,
startDate: startDate,
endDate: endDate,
shopAppointmentType: shopAppointmentType,
},
"service-location",
false
);
const numberOfDaysToEvaluate = 2;
const isGoodAvailability =
shopTimeSlots.data.days.filter((x) => x.timeSlots.length > 0).length >=
numberOfDaysToEvaluate;
const shopStatus = isGoodAvailability ? "high" : "low";
return shopStatus;
},
}, },
components: { components: {
loader, loader,

View file

@ -90,9 +90,6 @@ import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages"; import { errorMessages } from "@/constants/error-messages";
import baseMixin from "@/mixins/base-mixin.js"; import baseMixin from "@/mixins/base-mixin.js";
import { getAvailabilityRating } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
import { Provider } from "@/layouts/service-location/classes/provider";
import { AppointmentTypeStrings } from "@/constants/schedule-constants"; import { AppointmentTypeStrings } from "@/constants/schedule-constants";
import { import {
@ -115,7 +112,7 @@ export default {
answers: [], answers: [],
shopListButton: shopListButton, shopListButton: shopListButton,
shopIndex: 0, shopIndex: 0,
localShopProviderData: this.shopProviderData, // Why does parent manage this sometimes, but not all of the time localShopProviderData: this.shopProviderData, // Why does parent manage this sometimes, but not all of the time A: to prevent another call to get providers on initial load
selectedProviderNumber: null, // Revisit this, maybe not too hard selectedProviderNumber: null, // Revisit this, maybe not too hard
displayInvalidZipAlert: false, // part of big refactor of asyn calls displayInvalidZipAlert: false, // part of big refactor of asyn calls
displayNoShopsAlert: false, // part of big refactor of asyn calls displayNoShopsAlert: false, // part of big refactor of asyn calls
@ -139,27 +136,20 @@ export default {
modalHeaderText() { modalHeaderText() {
return this.getCmsContent("ShopQuestionWidget", "QuestionText"); return this.getCmsContent("ShopQuestionWidget", "QuestionText");
}, },
shopProviders() {
return this.localShopProviderData?.shopProviders ?? [];
},
modalFooterText() { modalFooterText() {
return this.getCmsContent("SaveLocationWidget", "Text"); return this.getCmsContent("SaveLocationWidget", "Text");
}, },
showMoreShopsLinkText() {
return this.getCmsContent("ShowMoreShopsLinkWidget", "Text");
},
modal() { modal() {
return this.$refs.shopQuestionModal; return this.$refs.shopQuestionModal;
}, },
shopProviders() {
return this.localShopProviderData?.shopProviders ?? [];
},
additionalButtonData() { additionalButtonData() {
const startDate = new Date();
const endDate = new Date();
endDate.setDate(startDate.getDate() + 6);
const formattedStartDate = startDate.toISOString().split("T")[0];
const formattedEndDate = endDate.toISOString().split("T")[0];
return { return {
availabilityRatingCallback: getAvailabilityRating,
startDate: formattedStartDate,
endDate: formattedEndDate,
// Used for availability indicators, could be refactored out of any availability indicator // Used for availability indicators, could be refactored out of any availability indicator
// logic if/when we are sure we'll never have separate drop off/ in shop logic // logic if/when we are sure we'll never have separate drop off/ in shop logic
shopAppointmentType: AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF, shopAppointmentType: AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF,
@ -170,9 +160,7 @@ export default {
return false; return false;
return this.shopIndex < this.shopProviders.length; return this.shopIndex < this.shopProviders.length;
}, },
showMoreShopsLinkText() {
return this.getCmsContent("ShowMoreShopsLinkWidget", "Text");
},
}, },
methods: { methods: {
openModal(event) { openModal(event) {
@ -363,25 +351,11 @@ export default {
const zipCode = shopProvider.address.zipCode; const zipCode = shopProvider.address.zipCode;
const distanceInMiles = Math.round(shopProvider.distanceInMiles * 2) / 2; const distanceInMiles = Math.round(shopProvider.distanceInMiles * 2) / 2;
const startDate = new Date();
const endDate = new Date();
endDate.setDate(startDate.getDate() + 6);
const formattedStartDate = startDate.toISOString().split("T")[0];
const formattedEndDate = endDate.toISOString().split("T")[0];
return { return {
buttonLabel: city, buttonLabel: city,
buttonLabelSubCopy: `${distanceInMiles} mi`, buttonLabelSubCopy: `${distanceInMiles} mi`,
buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`, buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`,
additionalButtonData: { additionalButtonData: this.additionalButtonData,
availabilityRatingCallback: getAvailabilityRating,
startDate: formattedStartDate,
endDate: formattedEndDate,
// Used for availability indicators, could be refactored out of any availability indicator
// logic if/when we are sure we'll never have separate drop off/ in shop logic
shopAppointmentType: AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF,
},
value: shopProvider.providerNumber, value: shopProvider.providerNumber,
}; };
}); });

View file

@ -49,8 +49,6 @@ import { errorMessages } from "@/constants/error-messages";
import baseMixin from "@/mixins/base-mixin.js"; import baseMixin from "@/mixins/base-mixin.js";
import { nextTick } from "vue"; import { nextTick } from "vue";
import { getAvailabilityRating } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
import { Provider } from "@/layouts/service-location/classes/provider"; import { Provider } from "@/layouts/service-location/classes/provider";
import { AppointmentTypeStrings } from "@/constants/schedule-constants"; import { AppointmentTypeStrings } from "@/constants/schedule-constants";
@ -109,17 +107,7 @@ export default {
return this.getCmsContent("ShowMoreShopsLinkWidget", "Text"); return this.getCmsContent("ShowMoreShopsLinkWidget", "Text");
}, },
additionalButtonData() { additionalButtonData() {
const startDate = new Date();
const endDate = new Date();
endDate.setDate(startDate.getDate() + 6);
const formattedStartDate = startDate.toISOString().split("T")[0];
const formattedEndDate = endDate.toISOString().split("T")[0];
return { return {
availabilityRatingCallback: getAvailabilityRating,
startDate: formattedStartDate,
endDate: formattedEndDate,
shopAppointmentType: this.selectedAppointmentType, shopAppointmentType: this.selectedAppointmentType,
}; };
}, },