diff --git a/src/constants/analytics.js b/src/constants/analytics.js index c0171209..8cf147e8 100644 --- a/src/constants/analytics.js +++ b/src/constants/analytics.js @@ -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({ diff --git a/src/constants/experiments.js b/src/constants/experiments.js index 9e959331..c336503b 100644 --- a/src/constants/experiments.js +++ b/src/constants/experiments.js @@ -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' }); diff --git a/src/helpers/adyen-helper.js b/src/helpers/adyen-helper.js index d1b5b571..70d2fe34 100644 --- a/src/helpers/adyen-helper.js +++ b/src/helpers/adyen-helper.js @@ -69,6 +69,7 @@ export function mapAdyenToIssPaymentMethod(adyenMethod) { const paymentMethodMap = { ["scheme"]: paymentMethods.CREDIT_CARD, ["afterpaytouch_US"]: paymentMethods.AFTERPAY, + ["afterpaytouch"]: paymentMethods.AFTERPAY, ["paypal"]: paymentMethods.PAYPAL, ["applepay"]: paymentMethods.APPLEPAY, }; diff --git a/src/helpers/service-location-helper.js b/src/helpers/service-location-helper.js index 72572256..13aced81 100644 --- a/src/helpers/service-location-helper.js +++ b/src/helpers/service-location-helper.js @@ -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); -} \ No newline at end of file +} diff --git a/src/iss-components/continue-modal/continue-modal.vue b/src/iss-components/continue-modal/continue-modal.vue index def01d34..8bca85ce 100644 --- a/src/iss-components/continue-modal/continue-modal.vue +++ b/src/iss-components/continue-modal/continue-modal.vue @@ -68,6 +68,7 @@ export default { }, methods: { openModal() { + this.pushEventToGA("existing_claim", "pop_up_displayed", this.mainStore.accountNameForEvents, true); this.$refs.continueModal.openModal(); }, setModalStatus(isOpened) { @@ -77,9 +78,11 @@ export default { this.$refs.continueModal.closeModal(); }, continueReferral() { + this.pushEventToGA("existing_claim", "finish_claim", this.mainStore.accountNameForEvents, true); this.$emit('continue-previous-referral'); }, startNewReferral() { + this.pushEventToGA("existing_claim", "start_new_claim", this.mainStore.accountNameForEvents, true); this.$emit('start-new-referral'); } } diff --git a/src/layouts/contact-details/contact-details.vue b/src/layouts/contact-details/contact-details.vue index b73d3fc4..a5c0c646 100644 --- a/src/layouts/contact-details/contact-details.vue +++ b/src/layouts/contact-details/contact-details.vue @@ -230,11 +230,15 @@ export default { }, watch: { isSameAsPolicyAddress(newValue) { + this.pushEventToGA("mobile_location", "same_as_policy_address", newValue ? "checked" : "unchecked", true); if (newValue) { this.copyPolicyAddressToServiceLocation(); } else { this.clearAddressFields(); } + }, + isVehicleProtected(newValue) { + this.pushEventToGA("mobile_location", "is_vehicle_protected", newValue, true); } }, methods: { diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index b4a68eb0..f0b1a150 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -60,6 +60,10 @@ + + + \ No newline at end of file diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index 92d8dd10..2b80ca23 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -68,6 +68,7 @@ :options="DamageCauseOptions" disableAutoFill :validationRules="rules.damageOption" + isRequired placeHolderText="Select an option" class="form-group" /> { + const formRoot = this.$el; + const requiredFieldCount = formRoot.querySelectorAll('[aria-required="true"]').length; + this.pushEventToGA("policy_info", "required_fields", requiredFieldCount.toString(), true); + }); + + this.mainStore.applicationUser.firstHit = false; + } + + // TODO: Check if we're coming from SFA + // eslint-disable-next-line + if (false) { + this.pushEventToGA("co_branded", "welcome_clicked_cta", "yes_clicked", 0); + this.pushEventToGA("visitor_info_welcome", "referring_site", "SFA", null); + } + else { + this.pushEventToGA("visitor_info_welcome", "referring_site", "ClientSite", null); + } + + this.pushEventToGA("visitor_info_welcome", "client_name", this.mainStore.accountNameForEvents, null); + }, computed: { DamageCauseOptions() { const damageCauseAnswers = this.getCmsContent( @@ -460,6 +490,20 @@ export default { this.answeredContinueModal = true; this.$refs.continueModal.closeModal(); } + }, + watch: { + 'welcomePageModel.policyZipCode': { + handler: async function (newZip) { + if (newZip.length === 5) { + this.pushEventToGA("policy_info", "policy_zip", newZip, true); + } + } + }, + 'welcomePageModel.damageCause': function (newCause) { + if (newCause) { + this.pushEventToGA("policy_info", "cause_of_loss", newCause, true); + } + } } }; diff --git a/src/mixins/experiment-mixin.js b/src/mixins/experiment-mixin.js index 5b1f7142..7f9a761e 100644 --- a/src/mixins/experiment-mixin.js +++ b/src/mixins/experiment-mixin.js @@ -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] diff --git a/src/store/index.js b/src/store/index.js index 8a4f1b34..aa56015a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -239,7 +239,8 @@ export const getDefaultState = () => ({ triggeredSiteEntry: false, // TODO not in save session duplicateOrders: [], hasSentSaveQuoteEmail: null, - coverageLookupAttempts: 0 + coverageLookupAttempts: 0, + firstHit: true }, issConfig: { clientName: 'Generic Insurance', // this is the default and will be overriden by the client's name @@ -445,7 +446,8 @@ export const useMainStore = defineStore({ .map((x) => x.settings) .reduce((r, c) => Object.assign(r, c), {}) ?? {}, originalDeductible: (state) => (state.order.damage.isRepair ? state.order.originalDeductible.repair : state.order.originalDeductible.replace), - currentDeductible: (state) => (state.order.damage.isRepair ? state.order.currentDeductible.repair : state.order.currentDeductible.replace) + currentDeductible: (state) => (state.order.damage.isRepair ? state.order.currentDeductible.repair : state.order.currentDeductible.replace), + accountNameForEvents: (state) => state.issConfig.clientName.replaceAll(" ", "").replaceAll("&", "amp") }, actions: { @@ -2587,6 +2589,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);