Merge pull request #1147 from Safelite/feature/richardson/INSR-8504

Mobile First Modal
This commit is contained in:
brich1212safe 2026-03-25 12:56:32 -04:00 committed by GitHub
commit 9c0eb957dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 510 additions and 28 deletions

View file

@ -11,22 +11,29 @@ const GaEvents = Object.freeze({
const GaCategories = Object.freeze({
API_RESPONSE: 'Api_Response',
CONFIRMATION_CLICKED: "confirmation clicked",
CONFIRMATION_CLICKED_INSHOP: "inshop confirmation clicked",
CONFIRMATION_CLICKED_MOBILE: "mobile confirmation clicked",
EVOX: 'Evox'
});
const GaActions = Object.freeze({
RESULT: 'Result',
CLICKED: 'Clicked',
NO: "no",
RESULT: 'Result',
SUBMITTED: 'Submitted',
VIF: 'vif',
SUBMITTED: 'Submitted'
YES: "yes",
});
const GaLabels = Object.freeze({
SUCCESS: 'Success',
ADDRESS_LOOKUP: 'Address_Look_up',
ERROR: 'Error',
LICENSE_PLATE_LOOKUP: 'License_Plate_Look_Up',
NO: "no",
SUCCESS: 'Success',
VIN_LOOKUP: 'Vin_Look_Up',
ADDRESS_LOOKUP: 'Address_Look_up'
YES: "yes",
});
const ValueToLogTypes = Object.freeze({

View file

@ -2,6 +2,7 @@ const experimentUniverses = Object.freeze({
ISS_FUNNEL: 'ISSFunnel',
ISS_FEATURETOGGLE_AREFEES_HIDDEN: 'NextGenISS_FeatureToggle_AreFeesHidden',
ISS_FEATURETOGGLE_AREFEES_OVERRIDDEN: 'NextGenISS_FeatureToggle_AreFeesOverridden',
ISS_MOBILE_FIRST_APPOINTMENTS: 'ISS_Mobile_First_Appointments',
ADYEN_PAYMENT_TEST: 'NextGenAdyenPaymentTest'
});
@ -12,6 +13,9 @@ const experimentSettings = Object.freeze({
ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_OVERRIDDEN: 'OverrideMobileFee',
ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN: 'HideRecycleFee',
ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_OVERRIDDEN: 'OverrideRecycleFee',
ISS_MOBILE_FIRST_MAX_MOBILE_DAYS: 'MaxMobileDays',
ISS_MOBILE_FIRST_MAX_PM_MOBILE_DAYS: 'MaxPmMobileDays',
ISS_MOBILE_FIRST_SHOW_FIRST_MOBILE_APPOINTMENT: 'ShowMobileFirstAppointment',
ISS_ENABLE_ADYEN_V1: 'ISS_Enable_Adyen_V1'
});

View file

@ -15,8 +15,23 @@ function processZipCodeResults(request) {
}));
}
export async function getZipCodeData(zipCode) {
return await processZipCodeResults(useMainStore().validateZip({ zip: zipCode }));
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 useMainStore().getShopTimeSlots(startDate, endDate, shopAppointmentType, providerNumber);
const numberOfDaysToEvaluate = 2;
const isGoodAvailability =
shopTimeSlots.data.days.filter((x) => x.timeSlots.length > 0).length
>= numberOfDaysToEvaluate;
const shopStatus = isGoodAvailability ? 'high' : 'low';
return Promise.resolve(shopStatus);
}
export async function getMobileZipCodeData(zipCode) {
@ -42,25 +57,6 @@ export async function getPricedMobileFeePart(serviceZipCode) {
return Promise.resolve(pricingResults[0]);
}
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 useMainStore().getShopTimeSlots(startDate, endDate, shopAppointmentType, providerNumber);
const numberOfDaysToEvaluate = 2;
const isGoodAvailability =
shopTimeSlots.data.days.filter((x) => x.timeSlots.length > 0).length
>= numberOfDaysToEvaluate;
const shopStatus = isGoodAvailability ? 'high' : 'low';
return Promise.resolve(shopStatus);
}
export function getProviderData() {
const mainStore = useMainStore();
const storeServiceLocation = mainStore.order.serviceLocation;
@ -73,6 +69,18 @@ export function getProviderData() {
return { storeServiceLocation, isMobileAppointment, storeSelectedProvider, serviceZipCode }
}
export async function getZipCodeData(zipCode) {
return await processZipCodeResults(useMainStore().validateZip({ zip: zipCode }));
}
export function mapTimeSlot(timeSlot, timeOfDay) {
return {
...timeSlot,
isDropoff: timeSlot.id.endsWith('DROP OFF'),
timeOfDay
};
}
export async function onProviderChanged() {
const { isMobileAppointment, storeSelectedProvider, serviceZipCode } = getProviderData();
if (!storeSelectedProvider) {
@ -101,4 +109,4 @@ export async function onProviderChanged() {
}
await settleAllPromises(promiseResultMap);
}
}

View file

@ -60,6 +60,10 @@
</div>
</div>
</div>
<suggestTimeslotModal
:ref="SUGGEST_TIMESLOT_MODAL_REF_NAME"
cmsWidgetName="SuggestTimeslotModal"
@confirmAppointmentClicked="autoSelectTimeslotConfirmed" />
</Form>
</template>
<script>
@ -70,8 +74,10 @@ import locationAlerts from '@/layouts/schedule-page/location-alerts/location-ale
import datePicker from '@/digital-components/date-picker/date-picker.vue';
import serviceLocation from '@/layouts/schedule-page/service-location/service-location.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import suggestTimeslotModal from '@/layouts/schedule-page/suggest-timeslot-modal/suggest-timeslot-modal.vue';
// Supporting files
import { experimentSettings, experimentUniverses } from '@/constants/experiments';
import {
AppointmentTypeStrings,
GET_MOBILE_TIME_SLOTS,
@ -91,13 +97,16 @@ import settleAllPromises from '@/helpers/layout-helper';
import showIssLoadingModal from '@/helpers/loading-modal-helper.js';
import {
getPricedMobileFeePart,
getZipCodeData
getMobileZipCodeData,
getZipCodeData,
mapTimeSlot
} from '@/helpers/service-location-helper';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';
// Define constants
const SUGGEST_TIMESLOT_MODAL_REF_NAME = 'SuggestTimeslotModal';
const TIME_SLOTS_CALL_DAYS_LIMIT = 15;
const getAvailableDates = async (
@ -219,6 +228,7 @@ export default {
datePicker,
serviceLocation,
siteFooter,
suggestTimeslotModal,
Form
},
mixins: [BaseFormMixin],
@ -323,9 +333,16 @@ export default {
zipCodeCtu: resultMap.zipCodeData?.zipCodeCtu
};
const mobileFirstObject = {
mobileProviderNumber: resultMap.providers?.mobileProviderNumber,
serviceabilityDetails: resultMap.serviceabilityDetails,
zipCode: initialServiceLocationObj.zipCode
}
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.serviceLocation.initializeComponent(serviceLocationData);
await vm.setData(resultMap.premiumFeeWithPrice, initialServiceLocationObj);
await vm.checkMobileFirstExperience(mobileFirstObject);
showIssLoadingModal(false);
});
},
@ -351,7 +368,8 @@ export default {
selectedServiceLocation: this.getServiceLocation(),
selectedServiceLocationCity: this.getServiceLocationCity(),
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
showDatePickerError: false
showDatePickerError: false,
SUGGEST_TIMESLOT_MODAL_REF_NAME
};
},
computed: {
@ -432,6 +450,185 @@ export default {
arePagePrerequisitesValid() {
return useMainStore().order.serviceLocation.zipCode !== null;
},
async autoSelectTimeslotConfirmed(emittedValue) {
if (this.mainStore.isNoComp || this.mainStore.isITAC) {
console.log('User is No Comp or ITAC, skipping mobile fee update on auto select timeslot confirmed');
// this.mainStore.updateMobileFee(this.mobileFeePart);
}
const providerToUse = {
providerNumber: emittedValue.mobileProviderNumber,
address: {
streetAddress: null,
city: null,
state: null,
zipCode: null,
zipCodeCtu: null
}
};
this.mainStore.updateServiceLocation({
state: emittedValue.zipCodeData.state,
zipCode: emittedValue.zipCodeData.zipCode,
zipCodeCtu: emittedValue.zipCodeData.zipCodeCtu,
appointmentType: AppointmentTypeStrings.MOBILE,
provider: providerToUse
});
const timeSlotToUse = {
date: emittedValue.date,
routeCode: emittedValue.timeSlot.id,
startTime: emittedValue.timeSlot.startTime,
endTime: emittedValue.timeSlot.endTime,
jobMaxMinutes: emittedValue.estimatedServiceMinutesMax,
jobMinMinutes: emittedValue.estimatedServiceMinutesMin,
};
this.mainStore.saveSchedule(timeSlotToUse);
showIssLoadingModal(true);
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
},
async checkMobileFirstExperience(mobileFirstObject = {}) {
const showMobileFirst = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_SHOW_FIRST_MOBILE_APPOINTMENT);
if (showMobileFirst) {
const pmMobileDaysLimit = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_MAX_PM_MOBILE_DAYS);
const mobileDaysLimit = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_MAX_MOBILE_DAYS);
const hasSelectedDate = !!this.getSelectedDate();
const isServicableMobile = mobileFirstObject.serviceabilityDetails?.isGlassServiceableMobile;
if (!hasSelectedDate && isServicableMobile && mobileFirstObject.mobileProviderNumber && mobileFirstObject.zipCode) {
const todayDateObject = new Date();
const todayDateString = convertDateToDateString(todayDateObject);
const calendarViewDirection = 'future';
const initialDays = 15;
const initialViewStartDate = todayDateString;
const initialEndDate = new Date();
initialEndDate.setDate(initialEndDate.getDate() + (initialDays - 1));
const initialViewEndDate = convertDateToDateString(initialEndDate);
const preSelectedDate = this.selectedDate;
const initialData = await getAvailableDates(
initialViewStartDate,
initialViewEndDate,
AppointmentTypeStrings.MOBILE,
mobileFirstObject.mobileProviderNumber,
mobileFirstObject.zipCode
).then((response) => ({
todayDate: todayDateString,
initialViewStartDate,
initialViewEndDate,
calendarViewDirection,
initialShopTimeSlotsResponse: response,
preSelectedDate,
initialDaysLoaded: initialDays,
daysFromStart: null
}))
.catch(() => {
return {
todayDate: todayDateString,
initialViewStartDate,
initialViewEndDate,
calendarViewDirection,
initialShopTimeSlotsResponse: { days: [] },
preSelectedDate,
initialDaysLoaded: initialDays,
daysFromStart: null
};
});
this.mobileDatesData = initialData;
const estimatedServiceMinutesMax = initialData.initialShopTimeSlotsResponse?.estimatedServiceMinutesMaximum || 120;
const estimatedServiceMinutesMin = initialData.initialShopTimeSlotsResponse?.estimatedServiceMinutesMinimum || 90;
const retTimeSlotsResponse = [];
initialData.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
const dateObjectToPush = {
date: selectableDate.date,
timeSlots: selectableDate.timeSlots,
morningTimeSlots: selectableDate.timeSlots.filter((timeSlot) => {
const timeHour = parseInt(timeSlot.startTime.split(':')[0], 10);
return timeHour < 12;
}).map((timeSlot) => mapTimeSlot(timeSlot, 'morning')),
afternoonTimeSlots: selectableDate.timeSlots.filter((timeSlot) => {
const timeHour = parseInt(timeSlot.startTime.split(':')[0], 10);
return timeHour >= 12;
}).map((timeSlot) => mapTimeSlot(timeSlot, 'afternoon')),
isSelected: false
};
if (dateObjectToPush.morningTimeSlots.length > 0) {
const findIndex = dateObjectToPush.morningTimeSlots.findIndex((timeSlot) => timeSlot.id.endsWith('DROP OFF'));
if (findIndex !== -1) {
const dropOffSlot = dateObjectToPush.morningTimeSlots.splice(findIndex, 1)[0];
dateObjectToPush.morningTimeSlots.unshift(dropOffSlot);
}
}
if (dateObjectToPush.afternoonTimeSlots.length > 0) {
const findIndex = dateObjectToPush.afternoonTimeSlots.findIndex((timeSlot) => timeSlot.id.endsWith('DROP OFF'));
if (findIndex !== -1) {
const dropOffSlot = dateObjectToPush.afternoonTimeSlots.splice(findIndex, 1)[0];
dateObjectToPush.afternoonTimeSlots.push(dropOffSlot);
}
}
retTimeSlotsResponse.push(dateObjectToPush);
});
let dateDifferenceForPmMobile = null;
const firstPmMobileDateWithTimeSlots = retTimeSlotsResponse.find((date) => {
const hasPmMobileTimeSlots = date.afternoonTimeSlots?.length > 0;
if (hasPmMobileTimeSlots && pmMobileDaysLimit) {
dateDifferenceForPmMobile = calcDaysBetweenDates(todayDateString, date.date);
return dateDifferenceForPmMobile <= pmMobileDaysLimit;
}
return hasPmMobileTimeSlots;
});
let dateDifferenceForMobile = null;
const firstMobileDateWithTimeSlots = retTimeSlotsResponse.find((date) => {
const hasMobileTimeSlots = date.morningTimeSlots?.length > 0;
const hasPmMobileTimeSlots = date.afternoonTimeSlots?.length > 0;
if (hasMobileTimeSlots || hasPmMobileTimeSlots) {
if (mobileDaysLimit) {
dateDifferenceForMobile = calcDaysBetweenDates(todayDateString, date.date);
return mobileDaysLimit && dateDifferenceForMobile <= mobileDaysLimit;
}
return true;
}
return hasPmMobileTimeSlots;
});
const zipCodeData = await getMobileZipCodeData(mobileFirstObject.zipCode);
if ((firstPmMobileDateWithTimeSlots || firstMobileDateWithTimeSlots) && zipCodeData?.isValid) {
zipCodeData.zipCode = mobileFirstObject.zipCode;
const timeSlotForAutoSelectionMobile = {
date: firstPmMobileDateWithTimeSlots ? firstPmMobileDateWithTimeSlots.date : firstMobileDateWithTimeSlots.date,
estimatedServiceMinutesMax,
estimatedServiceMinutesMin,
isRepair: this.mainStore.order.damage.isRepair,
mobileProviderNumber: mobileFirstObject.mobileProviderNumber,
timeSlot: firstPmMobileDateWithTimeSlots ? firstPmMobileDateWithTimeSlots.afternoonTimeSlots[0]
: (firstMobileDateWithTimeSlots.morningTimeSlots[0] || firstMobileDateWithTimeSlots.afternoonTimeSlots[0]),
zipCodeData
};
const dateObjectToUse = new Date(`${timeSlotForAutoSelectionMobile.date}T${timeSlotForAutoSelectionMobile.timeSlot.startTime}:00`);
timeSlotForAutoSelectionMobile.dateObject = dateObjectToUse;
timeSlotForAutoSelectionMobile.dayOfWeek = dateObjectToUse.toLocaleDateString('en-US', { weekday: 'long' });
const experiment = this.getExperimentByName(experimentUniverses.ISS_MOBILE_FIRST_APPOINTMENTS);
if (experiment && !experiment.isExposed) {
this.mainStore.logMobileFirstExperimentExposure();
}
this.$refs[SUGGEST_TIMESLOT_MODAL_REF_NAME].openModal(timeSlotForAutoSelectionMobile);
}
}
}
},
async setData(premiumFeeWithPriceResponse, initialServiceLocationObj) {
this.selectedServiceLocation = initialServiceLocationObj;
this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse

View file

@ -0,0 +1,259 @@
<template>
<div class="suggest-timeslot-modal-container">
<modal
ref="suggestTimeslotModal"
:onModalClosedCallback="onModalClosed">
<div>
<div class="header">{{ modalHeaderText }}</div>
<div class="subheader">{{ modalHeaderSubText }}</div>
</div>
<div>
<div class="message"
v-html="modalBodyText">
</div>
<div class="appointment-info"
v-html="modalAppointmentInformationText">
</div>
</div>
<div class="footer-container">
<div>
<button type="button" aria-live="polite" aria-label="Confirm Appointment" class="btn btn-danger confirm-appointment"
@click="confirmAppointmentClicked">
{{ modalCloseButtonText }}
</button>
</div>
<div>
<button type="button" aria-live="polite" aria-label="See more options" class="btn btn-link see-more-options"
@click="seeMoreOptionsClicked">
{{ modalFooterSubText }}
</button>
</div>
</div>
</modal>
</div>
</template>
<script>
import modal from '@/digital-components/modal/modal.vue';
import {
convertDateToTwoDigitDay,
getDisplayTextForDurationLength,
militaryToTwelveHourTime
} from '@/helpers/date-helper';
export default {
name: 'suggest-timeslot-modal',
components: {
modal
},
emits: ['confirm-appointment-clicked'],
data() {
return {
confirmedAppointment: false,
timeSlotForAutoSelectionMobile: {}
};
},
props: {
cmsWidgetName: {
type: String,
default: 'SuggestTimeslotModal'
}
},
computed: {
customAppointmentEstimate() {
return getDisplayTextForDurationLength(this.timeSlotForAutoSelectionMobile.estimatedServiceMinutesMin, this.timeSlotForAutoSelectionMobile.estimatedServiceMinutesMax)
},
customAppointmentWindow() {
return `${militaryToTwelveHourTime(this.timeSlotForAutoSelectionMobile?.timeSlot?.startTime)} - ${militaryToTwelveHourTime(this.timeSlotForAutoSelectionMobile?.timeSlot?.endTime)}`;
},
customDayOfWeek() {
return this.timeSlotForAutoSelectionMobile.dayOfWeek ? this.timeSlotForAutoSelectionMobile.dayOfWeek : '';
},
customDayOfWeekMonthDayYear() {
if (!this.timeSlotForAutoSelectionMobile?.date) {
return '';
}
const dayOfWeekToUse = this.customDayOfWeek;
const year = this.timeSlotForAutoSelectionMobile.dateObject.getFullYear();
const month = this.timeSlotForAutoSelectionMobile.dateObject.toLocaleString('en-US', { month: 'long' });
const day = convertDateToTwoDigitDay(this.timeSlotForAutoSelectionMobile.dateObject);
return `${dayOfWeekToUse}, ${month} ${day}, ${year}`;
},
modalAppointmentInformationText() {
return this.getCmsContent(this.cmsWidgetName, 'BodyText2')
.replaceAll('{custom:dowMonthDayYear}', this.customDayOfWeekMonthDayYear)
.replaceAll('{custom:appointmentEstimate}', this.customAppointmentEstimate)
.replaceAll('{custom:appointmentWindow}', this.customAppointmentWindow);
},
modalBodyText() {
return this.getCmsContent(this.cmsWidgetName, 'BodyText')
.replaceAll('{custom:damageType}', this.timeSlotForAutoSelectionMobile.isRepair ? 'repair' : 'replace',)
.replaceAll('{custom:dayOfWeekLong}', this.customDayOfWeek);
},
modalCloseButtonText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
},
modalFooterSubText() {
return 'See more options';
},
modalHeaderSubText() {
return this.getCmsContent(this.cmsWidgetName, 'SubheaderText');
},
modalHeaderText() {
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
},
},
methods: {
confirmAppointmentClicked() {
this.confirmedAppointment = true;
this.$emit('confirm-appointment-clicked', this.timeSlotForAutoSelectionMobile);
this.$refs.suggestTimeslotModal.closeModal();
},
onModalClosed() {
this.pushEvent();
this.confirmedAppointment = false;
this.timeSlotForAutoSelectionMobile = {};
},
openModal(timeSlotForAutoSelectionMobile) {
this.timeSlotForAutoSelectionMobile = timeSlotForAutoSelectionMobile;
this.$refs.suggestTimeslotModal.openModal();
},
pushEvent() {
const gaAction = this.confirmedAppointment ? this.GaActions.YES : this.GaActions.NO;
if (this.timeSlotForAutoSelectionMobile && this.timeSlotForAutoSelectionMobile.timeSlot) {
this.pushEventToGA(
this.GaCategories.CONFIRMATION_CLICKED,
gaAction,
this.timeSlotForAutoSelectionMobile.timeSlot.startTime +
"-" +
this.timeSlotForAutoSelectionMobile.timeSlot.endTime +
" " +
this.timeSlotForAutoSelectionMobile.date,
true
);
}
},
seeMoreOptionsClicked() {
this.$refs.suggestTimeslotModal.closeModal();
},
footerButtonClick() {
this.$refs.suggestTimeslotModal.closeModal();
},
}
};
</script>
<style lang="scss" scoped>
.suggest-timeslot-modal-container {
.modal {
padding-right: 0;
}
:deep(.modal) {
.modal-dialog {
@include media-breakpoint-up(xs) {
width: auto;
max-width: unset;
}
@include media-breakpoint-up(xl) {
width: 37.5rem;
max-width: 37.5rem;
}
.modal-content {
width: 22rem;
max-width: 22rem;
padding: 1.5rem 0;
border-radius: 0.5rem;
line-height: 1.5rem;
.modal-header {
padding: 0;
}
.modal-body {
padding: 0 1rem;
}
.modal-footer {
display: none;
}
.header {
margin-top: 1rem;
color: #db0020;
text-align: center;
text-transform: uppercase;
letter-spacing: 0.03em;
font-weight: 600;
font-size: 0.875rem;
}
.subheader {
color: black;
text-align: center;
letter-spacing: 0.03em;
font-weight: 400;
font-size: 1.25rem;
line-height: 2rem;
}
.message {
margin-top: 1.5rem;
color: #525656;
letter-spacing: 0.03em;
font-weight: 400;
font-size: 1rem;
line-height: 1.625rem;
.emphasize {
color: black;
font-weight: 600;
}
}
.appointment-info {
margin-top: 1rem;
padding: 1rem;
background-color: #f4f4f4;
letter-spacing: 0.03em;
font-weight: 400;
font-size: 0.875rem;
.emphasize {
color: black;
font-weight: 600;
margin-right: 0.25rem;
}
}
.footer-container {
margin-top: 1.5rem;
padding: 0 1.5rem;
border: none;
.confirm-appointment {
width: 100%;
padding: .75rem 0;
border-radius: 4.5rem;
letter-spacing: 0.03em;
font-weight: 600;
font-size: 1rem;
}
.see-more-options {
text-align: center;
width: 100%;
margin-top: 1.5rem;
letter-spacing: 0.03em;
font-weight: 600;
font-size: 1rem;
line-height: 1.625rem;
}
}
}
}
}
}
</style>

View file

@ -8,6 +8,10 @@ export default {
hasSetting(settingName) {
return Object.hasOwn(useMainStore().experimentSettings, settingName);
},
getExperimentByName(experimentName) {
const experiment = useMainStore().applicationUser.experiments.find((e) => e.universeName === experimentName);
return experiment ? experiment : null;
},
getSettingValue(settingName) {
return this.hasSetting(settingName)
? useMainStore().experimentSettings[settingName]

View file

@ -2587,6 +2587,9 @@ export const useMainStore = defineStore({
}
);
},
logMobileFirstExperimentExposure() {
this.logExperimentIfExists(issPageValues.SCHEDULE_PAGE, experimentUniverses.ISS_MOBILE_FIRST_APPOINTMENTS);
},
logWelcomePageExperiments(issPage) {
this.logExperimentIfExists(issPage, experimentUniverses.ISS_FEATURETOGGLE_AREFEES_HIDDEN);
this.logExperimentIfExists(issPage, experimentUniverses.ISS_FEATURETOGGLE_AREFEES_OVERRIDDEN);