Merge branch 'release/2025.05.01' into feature/CASH-464

This commit is contained in:
Adam Caouette 2025-04-23 11:59:32 -04:00
commit bde52cd2c7
19 changed files with 292 additions and 373 deletions

View file

@ -35,7 +35,7 @@ module.exports = {
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
coverageThreshold: { coverageThreshold: {
global: { global: {
statements: 74, statements: 72,
}, },
}, },
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit // Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit

View file

@ -0,0 +1,66 @@
/*
The code below is generated from salesforce but modified in the following ways:
* Only the javascript inside the second <script> tag in the provided salesforce code is copy pasted
* CSS is not copied in
* First <script> tag loading in the file from the CDN is not copied in
* The only custom code added here is `let embedded_svc = window.embedded_svc` in the first line of the `initESW` function
and the wrapper exported function `initializeSalesforceWebChatForDev`
*/
export function initializeSalesforceWebchatForDev() {
var initESW = function (gslbBaseURL) {
let embedded_svc = window.embedded_svc;
embedded_svc.settings.displayHelpButton = true; //Or false
embedded_svc.settings.language = ""; //For example, enter 'en' or 'en-US'
//embedded_svc.settings.defaultMinimizedText = '...'; //(Defaults to Chat with an Expert)
//embedded_svc.settings.disabledMinimizedText = '...'; //(Defaults to Agent Offline)
//embedded_svc.settings.loadingText = ''; //(Defaults to Loading)
//embedded_svc.settings.storageDomain = 'yourdomain.com'; //(Sets the domain for your deployment so that visitors can navigate subdomains during a chat session)
// Settings for Chat
//embedded_svc.settings.directToButtonRouting = function(prechatFormData) {
// Dynamically changes the button ID based on what the visitor enters in the pre-chat form.
// Returns a valid button ID.
//};
//embedded_svc.settings.prepopulatedPrechatFields = {}; //Sets the auto-population of pre-chat form fields
//embedded_svc.settings.fallbackRouting = []; //An array of button IDs, user IDs, or userId_buttonId
//embedded_svc.settings.offlineSupportMinimizedText = '...'; //(Defaults to Contact Us)
embedded_svc.settings.enabledFeatures = ["LiveAgent"];
embedded_svc.settings.entryFeature = "LiveAgent";
embedded_svc.init(
"https://safelite2--dev.sandbox.my.salesforce.com",
"https://safelite2--dev.sandbox.my.salesforce-sites.com/chat",
gslbBaseURL,
"00D6s0000008r6A",
"Sales_Central_Snap_in",
{
baseLiveAgentContentURL:
"https://c.la12s-core1.sfdc-8tgtt5.salesforceliveagent.com/content",
deploymentId: "572Wr0000017xKX",
buttonId: "573Wr000000CpgH",
baseLiveAgentURL: "https://d.la12s-core1.sfdc-8tgtt5.salesforceliveagent.com/chat",
eswLiveAgentDevName:
"EmbeddedServiceLiveAgent_Parent04IWr000003yKq9MAE_1961681659a",
isOfflineSupportEnabled: false,
}
);
};
if (!window.embedded_svc) {
var s = document.createElement("script");
s.setAttribute(
"src",
"https://safelite2--dev.sandbox.my.salesforce.com/embeddedservice/5.0/esw.min.js"
);
s.onload = function () {
initESW(null);
};
document.body.appendChild(s);
} else {
initESW("https://service.force.com");
}
}

View file

@ -0,0 +1,63 @@
/*
The code below is generated from salesforce but modified in the following ways:
* Only the javascript inside the second <script> tag in the provided salesforce code is copy pasted
* CSS is not copied in
* First <script> tag loading in the file from the CDN is not copied in
* The only custom code added here is `let embedded_svc = window.embedded_svc` in the first line of the `initESW` function
and the wrapper exported function `initializeSalesforceWebChatForProd`
*/
export function initializeSalesforceWebchatForProd(embedded_svc) {
var initESW = function (gslbBaseURL) {
let embedded_svc = window.embedded_svc;
embedded_svc.settings.displayHelpButton = true; //Or false
embedded_svc.settings.language = ""; //For example, enter 'en' or 'en-US'
//embedded_svc.settings.defaultMinimizedText = '...'; //(Defaults to Chat with an Expert)
//embedded_svc.settings.disabledMinimizedText = '...'; //(Defaults to Agent Offline)
//embedded_svc.settings.loadingText = ''; //(Defaults to Loading)
//embedded_svc.settings.storageDomain = 'yourdomain.com'; //(Sets the domain for your deployment so that visitors can navigate subdomains during a chat session)
// Settings for Chat
//embedded_svc.settings.directToButtonRouting = function(prechatFormData) {
// Dynamically changes the button ID based on what the visitor enters in the pre-chat form.
// Returns a valid button ID.
//};
//embedded_svc.settings.prepopulatedPrechatFields = {}; //Sets the auto-population of pre-chat form fields
//embedded_svc.settings.fallbackRouting = []; //An array of button IDs, user IDs, or userId_buttonId
//embedded_svc.settings.offlineSupportMinimizedText = '...'; //(Defaults to Contact Us)
embedded_svc.settings.enabledFeatures = ["LiveAgent"];
embedded_svc.settings.entryFeature = "LiveAgent";
embedded_svc.init(
"https://safelite2.my.salesforce.com",
"https://safelite2.my.salesforce-sites.com/chat",
gslbBaseURL,
"00D3t000004nvsT",
"Sales_Central_Snap_in",
{
baseLiveAgentContentURL:
"https://c.la13-core2.sfdc-lywfpd.salesforceliveagent.com/content",
deploymentId: "5723t0000008wWB",
buttonId: "5733t000000D90z",
baseLiveAgentURL: "https://d.la13-core2.sfdc-lywfpd.salesforceliveagent.com/chat",
eswLiveAgentDevName:
"EmbeddedServiceLiveAgent_Parent04I3t000000Cq0SEAS_188de1871ea",
isOfflineSupportEnabled: false,
}
);
};
if (!window.embedded_svc) {
var s = document.createElement("script");
s.setAttribute("src", "https://safelite2.my.salesforce.com/embeddedservice/5.0/esw.min.js");
s.onload = function () {
initESW(null);
};
document.body.appendChild(s);
} else {
initESW("https://service.force.com");
}
}

View file

@ -0,0 +1,67 @@
/*
The code below is generated from salesforce but modified in the following ways:
* Only the javascript inside the second <script> tag in the provided salesforce code is copy pasted
* CSS is not copied in
* First <script> tag loading in the file from the CDN is not copied in
* The only custom code added here is `let embedded_svc = window.embedded_svc` in the first line of the `initESW` function
and the wrapper exported function `initializeSalesforceWebChatForQa`
*/
export function initializeSalesforceWebchatForQa() {
var initESW = function (gslbBaseURL) {
let embedded_svc = window.embedded_svc;
embedded_svc.settings.displayHelpButton = true; //Or false
embedded_svc.settings.language = ""; //For example, enter 'en' or 'en-US'
//embedded_svc.settings.defaultMinimizedText = '...'; //(Defaults to Chat with an Expert)
//embedded_svc.settings.disabledMinimizedText = '...'; //(Defaults to Agent Offline)
//embedded_svc.settings.loadingText = ''; //(Defaults to Loading)
//embedded_svc.settings.storageDomain = 'yourdomain.com'; //(Sets the domain for your deployment so that visitors can navigate subdomains during a chat session)
// Settings for Chat
//embedded_svc.settings.directToButtonRouting = function(prechatFormData) {
// Dynamically changes the button ID based on what the visitor enters in the pre-chat form.
// Returns a valid button ID.
//};
//embedded_svc.settings.prepopulatedPrechatFields = {}; //Sets the auto-population of pre-chat form fields
//embedded_svc.settings.fallbackRouting = []; //An array of button IDs, user IDs, or userId_buttonId
//embedded_svc.settings.offlineSupportMinimizedText = '...'; //(Defaults to Contact Us)
embedded_svc.settings.enabledFeatures = ["LiveAgent"];
embedded_svc.settings.entryFeature = "LiveAgent";
embedded_svc.init(
"https://safelite2--safeliteua.sandbox.my.salesforce.com",
"https://safelite2--safeliteua.sandbox.my.salesforce-sites.com/chat",
gslbBaseURL,
"00DDJ000000HRqO",
"Sales_Central_Snap_in",
{
baseLiveAgentContentURL:
"https://c.la12s-core1.sfdc-8tgtt5.salesforceliveagent.com/content",
deploymentId: "572DJ00000001j3",
buttonId: "573DJ00000001ur",
baseLiveAgentURL: "https://d.la12s-core1.sfdc-8tgtt5.salesforceliveagent.com/chat",
eswLiveAgentDevName:
"EmbeddedServiceLiveAgent_Parent04IDJ0000008OZk2AM_1883057c9a6",
isOfflineSupportEnabled: false,
}
);
};
if (!window.embedded_svc) {
var s = document.createElement("script");
s.setAttribute(
"src",
"https://safelite2--safeliteua.sandbox.my.salesforce.com/embeddedservice/5.0/esw.min.js"
);
s.onload = function () {
initESW(null);
};
document.body.appendChild(s);
} else {
initESW("https://service.force.com");
}
}

View file

@ -0,0 +1,57 @@
<template>
<span class="salesforce-webchat"></span>
</template>
<script>
// Supporting files
import { initializeSalesforceWebchatForDev } from "./salesforce-helper-dev";
import { initializeSalesforceWebchatForQa } from "./salesforce-helper-qa";
import { initializeSalesforceWebchatForProd } from "./salesforce-helper-prod";
export default {
name: "salesforceWebchat",
data() {
return {};
},
props: {
hideSalesforceWebchatLaunchButton: {
type: Boolean,
default: false,
},
},
mounted() {
// Load in script from salesforce CDN
const script = document.createElement("script");
script.src = "https://service.force.com/embeddedservice/5.0/esw.min.js";
script.onload = () => {
switch (process.env.VUE_APP_CURRENT_ENVIRONMENT) {
case "Prod":
initializeSalesforceWebchatForProd();
break;
case "QA":
case "SysTest":
initializeSalesforceWebchatForQa();
break;
case "Dev":
case "Localhost":
initializeSalesforceWebchatForDev();
break;
}
};
document.body.appendChild(script);
},
methods: {},
computed: {},
components: {},
};
</script>
<style type="text/css">
.embeddedServiceHelpButton .helpButton .uiButton {
background-color: #167cac;
font-family: "Arial", sans-serif;
}
.embeddedServiceHelpButton .helpButton .uiButton:focus {
outline: 1px solid #167cac;
}
</style>

View file

@ -5,6 +5,7 @@
:class="[ :class="[
this.buttonLabelSubCopy ? 'has-subheader' : '', this.buttonLabelSubCopy ? 'has-subheader' : '',
this.additionalButtonData.isInsuranceSelected ? 'is-insurance' : '', this.additionalButtonData.isInsuranceSelected ? 'is-insurance' : '',
this.hasPackageDiscount() ? 'has-package-discount' : '',
]" ]"
for="testradio"> for="testradio">
<div class="package-specs"> <div class="package-specs">
@ -54,12 +55,7 @@
v-html="this.buttonFooterCopy"></div> v-html="this.buttonFooterCopy"></div>
</div> </div>
<div <div v-if="hasPackageDiscount()" class="special-save-box">
v-if="
this.additionalButtonData.servicePackageDiscount &&
this.additionalButtonData.Text
"
class="special-save-box">
<span v-html="this.additionalButtonData.Text"></span> <span v-html="this.additionalButtonData.Text"></span>
</div> </div>
<span class="pricing-info"> <span class="pricing-info">
@ -144,6 +140,11 @@ export default {
truncatedSinglePayment() { truncatedSinglePayment() {
return "$" + Math.trunc(this.buttonAuxillaryCopy.replace("$", "")); return "$" + Math.trunc(this.buttonAuxillaryCopy.replace("$", ""));
}, },
hasPackageDiscount() {
return (
this.additionalButtonData.servicePackageDiscount && this.additionalButtonData.Text
);
},
}, },
}; };
</script> </script>
@ -212,12 +213,6 @@ export default {
} }
&.has-subheader { &.has-subheader {
min-height: 150px;
&.is-insurance {
min-height: 72px;
}
& > .package-specs { & > .package-specs {
& > div:first-of-type { & > div:first-of-type {
display: flex; display: flex;
@ -225,6 +220,10 @@ export default {
} }
} }
&.has-package-discount {
min-height: 150px;
}
&:before { &:before {
content: ""; content: "";
position: relative; position: relative;

View file

@ -2,6 +2,7 @@
<div <div
class="funnel-header d-flex justify-content-center align-items-center flex-column" class="funnel-header d-flex justify-content-center align-items-center flex-column"
v-if="imageSrc"> v-if="imageSrc">
<salesforceWebchat hideSalesforceWebchatLaunchButton />
<img class="logo-image img-fluid" :src="imageSrc" alt="Safelite logo" /> <img class="logo-image img-fluid" :src="imageSrc" alt="Safelite logo" />
<!-- // menu-modal temporarily not in use until the hamburger menu is re-implemented for use with the progress bar. See display: none below. --> <!-- // menu-modal temporarily not in use until the hamburger menu is re-implemented for use with the progress bar. See display: none below. -->
<menuModal /> <menuModal />
@ -26,6 +27,7 @@ import alert from "@/ux-components/alert/alert";
import eventBus from "@/helpers/event-bus/event-bus"; import eventBus from "@/helpers/event-bus/event-bus";
import { globalEvents } from "@/constants/events"; import { globalEvents } from "@/constants/events";
import menuModal from "@/fmg-components/funnel-header/menu-modal/menu-modal"; import menuModal from "@/fmg-components/funnel-header/menu-modal/menu-modal";
import salesforceWebchat from "../../digital-components/salesforce-webchat/salesforce-webchat.vue";
// Constants // Constants
const ALERT_DURATION = 3000; // millisecond time to display alert before dismissal const ALERT_DURATION = 3000; // millisecond time to display alert before dismissal
@ -39,6 +41,10 @@ export default {
}, },
props: { props: {
cmsWidgetName: String, cmsWidgetName: String,
hideSalesforceWebchatLaunchButton: {
type: Boolean,
default: false,
},
}, },
computed: { computed: {
imageSrc() { imageSrc() {
@ -62,6 +68,7 @@ export default {
components: { components: {
alert, alert,
menuModal, menuModal,
salesforceWebchat,
}, },
mounted() { mounted() {
// Check if alert event is on the bus // Check if alert event is on the bus

View file

@ -182,39 +182,6 @@ describe("address-lookup.vue", () => {
// Assert // Assert
expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true); expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true);
}); });
test("should show the AlertNoService when displayNoServiceAlert is true", async () => {
const { wrapper } = setupMocks({
isZipServiceable: true,
displayNoServiceAlert: true,
lookupVinbyAddressResponse: {
isStatePermissible: true,
vinVehicles: [], // Return no vehicles
},
});
// Set displayNoServiceAlert to true
await wrapper.setData({ displayNoServiceAlert: true });
// Check if the AlertNoService component is rendered
const alertNoService = wrapper.findComponent({ ref: "AlertNoService" });
expect(alertNoService.exists()).toBe(true);
});
test("should hide the AlertNoService when displayNoServiceAlert is false", async () => {
const { wrapper } = setupMocks({
isZipServiceable: true,
displayNoServiceAlert: false,
lookupVinbyAddressResponse: {
isStatePermissible: true,
vinVehicles: [], // Return no vehicles
},
});
// Ensure displayNoServiceAlert is false
await wrapper.setData({ displayNoServiceAlert: false });
// Check if the AlertNoService component is not rendered
const alertNoService = wrapper.findComponent({ ref: "AlertNoService" });
expect(alertNoService.exists()).toBe(false);
});
}); });
describe("navigation", () => { describe("navigation", () => {
@ -774,18 +741,6 @@ function setupMocks({
wrapper.vm.setCmsContent = jest.fn(); wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.$refs.navbar.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$refs.navbar.removeLoader = jest.fn(); wrapper.vm.$refs.navbar.removeLoader = jest.fn();
const closestShops = {
data: {
providers: [
{ id: 1, name: "Shop 1" },
{ id: 2, name: "Shop 2" },
],
},
};
wrapper.vm.findClosestApplicableShops = jest.fn().mockImplementation(() => {
return new Promise((resolve) => resolve(closestShops));
});
return { wrapper }; return { wrapper };
} }

View file

@ -81,20 +81,13 @@
</div> </div>
</div> </div>
</transition> </transition>
<alert
ref="AlertNoService"
v-if="displayNoServiceAlert"
class="my-4"
cmsWidgetName="AlertNoServiceWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isDisabled="!meta.valid" :isDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction" @ForwardClicked="forwardButtonAction"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
:isForwardActionDisabled="!meta.valid || displayNoServiceAlert" /> :isForwardActionDisabled="!meta.valid" />
</div> </div>
</div> </div>
</div> </div>
@ -171,8 +164,6 @@ export default {
emailOrSms: this.getEmailOrSmsFromStore(), emailOrSms: this.getEmailOrSmsFromStore(),
}, },
serviceZipCode: this.getServiceZipFromStore(), serviceZipCode: this.getServiceZipFromStore(),
carId: this.getCarIdfromStore(),
isHeavyTruck: this.getIsVehicleHeavyTruckFromStore(),
displayNonServiceableZipAlert: false, displayNonServiceableZipAlert: false,
displayVinNotFoundAlert: false, displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false, displayMatchedDifferentVehicleAlert: false,
@ -184,7 +175,6 @@ export default {
displayInvalidZipAlert: false, displayInvalidZipAlert: false,
showServiceZipField: this.getServiceZipFromStore(), showServiceZipField: this.getServiceZipFromStore(),
isZipServiceable: false, isZipServiceable: false,
displayNoServiceAlert: false,
}; };
}, },
methods: { methods: {
@ -229,19 +219,6 @@ export default {
getServiceZipFromStore() { getServiceZipFromStore() {
return this.$store.getters.order.serviceLocation.zipCode; return this.$store.getters.order.serviceLocation.zipCode;
}, },
getCarIdfromStore() {
return store.getters.vehicle.carId;
},
getIsVehicleHeavyTruckFromStore() {
return store.getters.isHeavyTruckVehicle;
},
async findClosestApplicableShops() {
return await this.dispatchStoreActionWithLogging(
storeActions.GET_CLOSEST_APPLICABLE_SHOPS,
{ zip: this.serviceZipCode, carId: this.carId },
"address-lookup"
);
},
async forwardButtonAction() { async forwardButtonAction() {
this.resetWarningsAndErrors(); this.resetWarningsAndErrors();
@ -301,17 +278,6 @@ export default {
return this.$refs.navbar.removeLoader(); return this.$refs.navbar.removeLoader();
} }
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
if (this.serviceZipCode != null && this.isHeavyTruck) {
const closestShops = await this.findClosestApplicableShops(
this.serviceZipCode,
this.carId
);
this.displayNoServiceAlert = !closestShops?.data?.providers?.length;
if (this.displayNoServiceAlert) {
return this.$refs.navbar.removeLoader();
}
}
const carsFound = resultMap.vinLookupResponse.vinVehicles; const carsFound = resultMap.vinLookupResponse.vinVehicles;
// Handle cases for different amounts of VINS found for the address. // Handle cases for different amounts of VINS found for the address.
@ -463,7 +429,6 @@ export default {
this.displayNonServiceableZipAlert = false; this.displayNonServiceableZipAlert = false;
this.displayMatchedDifferentVehicleAlert = false; this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false; this.displayVinLookupByHomeAddressNotAllowedAlert = false;
this.displayNoServiceAlert = false;
}, },
}, },
mounted() { mounted() {
@ -515,7 +480,6 @@ export default {
handler(newValue) { handler(newValue) {
// If they modify the service zip code, then hide the error message. // If they modify the service zip code, then hide the error message.
this.displayNonServiceableZipAlert = false; this.displayNonServiceableZipAlert = false;
this.displayNoServiceAlert = false;
}, },
}, },
showServiceZipField: { showServiceZipField: {

View file

@ -5,7 +5,10 @@
<div class="container-fluid pb-2"> <div class="container-fluid pb-2">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" /> <funnelHeader
cmsWidgetName="FunnelHeaderWidget"
ref="funnelHeader"
hideSalesforceWebchatLaunchButton />
</div> </div>
</div> </div>
<div class="row justify-content-center"> <div class="row justify-content-center">

View file

@ -611,42 +611,6 @@ describe("license-plate-lookup.vue", () => {
expect(arePagePrerequisitesValid).toBe(false); expect(arePagePrerequisitesValid).toBe(false);
}); });
}); });
describe("alerts", () => {
test("should show the AlertNoService when displayNoServiceAlert is true", async () => {
const { wrapper } = setupMocks({
isZipServiceable: true,
displayNoServiceAlert: true,
lookupVinbyAddressResponse: {
isStatePermissible: true,
vinVehicles: [], // Return no vehicles
},
});
// Set displayNoServiceAlert to true
await wrapper.setData({ displayNoServiceAlert: true });
// Check if the AlertNoService component is rendered
const alertNoService = wrapper.findComponent({ ref: "AlertNoService" });
expect(alertNoService.exists()).toBe(true);
});
test("should hide the AlertNoService when displayNoServiceAlert is false", async () => {
const { wrapper } = setupMocks({
isZipServiceable: true,
displayNoServiceAlert: false,
lookupVinbyAddressResponse: {
isStatePermissible: true,
vinVehicles: [], // Return no vehicles
},
});
// Ensure displayNoServiceAlert is false
await wrapper.setData({ displayNoServiceAlert: false });
// Check if the AlertNoService component is not rendered
const alertNoService = wrapper.findComponent({ ref: "AlertNoService" });
expect(alertNoService.exists()).toBe(false);
});
});
}); });
function setupMocks({ function setupMocks({
@ -752,18 +716,5 @@ function setupMocks({
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
wrapper.vm.$refs.navbar.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$refs.navbar.removeLoader = jest.fn(); wrapper.vm.$refs.navbar.removeLoader = jest.fn();
const closestShops = {
data: {
providers: [
{ id: 1, name: "Shop 1" },
{ id: 2, name: "Shop 2" },
],
},
};
wrapper.vm.findClosestApplicableShops = jest.fn().mockImplementation(() => {
return new Promise((resolve) => resolve(closestShops));
});
return { wrapper, apiPromise }; return { wrapper, apiPromise };
} }

View file

@ -77,14 +77,6 @@
alertClass="alert-warning" alertClass="alert-warning"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert
ref="AlertNoService"
v-if="displayNoServiceAlert"
class="my-4"
cmsWidgetName="AlertNoServiceWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<navbar <navbar
ref="navbar" ref="navbar"
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
@ -166,8 +158,6 @@ export default {
registrationZipCode: this.getRegistrationZipFromStore() ?? this.$route.query.zipcode, registrationZipCode: this.getRegistrationZipFromStore() ?? this.$route.query.zipcode,
emailOrSms: this.getEmailOrSmsFromStore(), emailOrSms: this.getEmailOrSmsFromStore(),
serviceZipCode: this.getServiceZipFromStore(), serviceZipCode: this.getServiceZipFromStore(),
carId: this.getCarIdfromStore(),
isHeavyTruck: this.getIsVehicleHeavyTruckFromStore(),
displayNonServiceableZipAlert: false, displayNonServiceableZipAlert: false,
displayVinNotFoundAlert: false, displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false, displayMatchedDifferentVehicleAlert: false,
@ -178,7 +168,6 @@ export default {
displayInvalidZipAlert: false, displayInvalidZipAlert: false,
showServiceZipField: this.getServiceZipFromStore(), showServiceZipField: this.getServiceZipFromStore(),
isZipServiceable: false, isZipServiceable: false,
displayNoServiceAlert: false,
}; };
}, },
methods: { methods: {
@ -211,19 +200,6 @@ export default {
getServiceZipFromStore() { getServiceZipFromStore() {
return this.$store.getters.order.serviceLocation.zipCode; return this.$store.getters.order.serviceLocation.zipCode;
}, },
getCarIdfromStore() {
return store.getters.vehicle.carId;
},
getIsVehicleHeavyTruckFromStore() {
return store.getters.isHeavyTruckVehicle;
},
async findClosestApplicableShops() {
return await this.dispatchStoreActionWithLogging(
storeActions.GET_CLOSEST_APPLICABLE_SHOPS,
{ zip: this.serviceZipCode, carId: this.carId },
"license-plate-lookup"
);
},
async forwardButtonAction() { async forwardButtonAction() {
this.resetWarningsAndErrors(); this.resetWarningsAndErrors();
@ -281,17 +257,6 @@ export default {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
return this.$refs.navbar.removeLoader(); return this.$refs.navbar.removeLoader();
} }
if (this.isHeavyTruck) {
const closestShops = await this.findClosestApplicableShops(
this.serviceZipCode,
this.carId
);
this.displayNoServiceAlert = !closestShops?.data?.providers?.length;
if (this.displayNoServiceAlert) {
return this.$refs.navbar.removeLoader();
}
}
// Check if the CarId has changed. // Check if the CarId has changed.
this.isCarIdDifferent = this.isCarIdDifferent =
vinLookup.data.vehicle.carId !== this.$store.getters.vehicle.carId; vinLookup.data.vehicle.carId !== this.$store.getters.vehicle.carId;
@ -406,7 +371,6 @@ export default {
this.displayMatchedDifferentVehicleAlert = false; this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false; this.displayVinLookupByHomeAddressNotAllowedAlert = false;
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
this.displayNoServiceAlert = false;
}, },
}, },
mounted() { mounted() {
@ -451,7 +415,6 @@ export default {
serviceZipCode() { serviceZipCode() {
// If they modify the service zip code, then hide the error message. // If they modify the service zip code, then hide the error message.
this.displayNonServiceableZipAlert = false; this.displayNonServiceableZipAlert = false;
this.displayNoServiceAlert = false;
this.$refs.navbar.updateButtonText( this.$refs.navbar.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );

View file

@ -100,7 +100,7 @@ describe("appointment-type-question.vue", () => {
]); ]);
}); });
it("Should display only the In-Shop answer when only in-shop service is available", async () => { it("Should display only the In-Shop and Drop-Off answers when only in-shop service is available", async () => {
// Arrange/Act // Arrange/Act
const { wrapper } = setupMocks({ const { wrapper } = setupMocks({
mixins: [mockMixin], mixins: [mockMixin],
@ -108,7 +108,6 @@ describe("appointment-type-question.vue", () => {
cmsWidgetName: cmsWidgetName, cmsWidgetName: cmsWidgetName,
isServiceableInshop: true, isServiceableInshop: true,
isServiceableMobile: false, isServiceableMobile: false,
isServiceableDropoff: false,
}, },
mountOptions: { mountOptions: {
attachTo: document.body, attachTo: document.body,
@ -124,6 +123,13 @@ describe("appointment-type-question.vue", () => {
SubWidgetName: "", SubWidgetName: "",
Text: "In-shop", Text: "In-shop",
}, },
{
AnswerImageUrl: "",
Name: "Dropoff",
SubText: "",
SubWidgetName: "",
Text: "Drop-off",
},
]); ]);
}); });

View file

@ -32,7 +32,6 @@ export default {
cmsWidgetName: String, cmsWidgetName: String,
isServiceableMobile: Boolean, isServiceableMobile: Boolean,
isServiceableInshop: Boolean, isServiceableInshop: Boolean,
isServiceableDropoff: Boolean,
mobileFeeApplies: Boolean, mobileFeeApplies: Boolean,
}, },
computed: { computed: {
@ -46,7 +45,7 @@ export default {
const shouldShowMobile = this.isServiceableMobile; const shouldShowMobile = this.isServiceableMobile;
const shouldShowInshop = this.isServiceableInshop; const shouldShowInshop = this.isServiceableInshop;
const shouldShowDropoff = const shouldShowDropoff =
this.isServiceableDropoff && !this.$store.getters.damage.isRepair; this.isServiceableInshop && !this.$store.getters.damage.isRepair;
var answers = this.answersFromCms var answers = this.answersFromCms
? this.answersFromCms.filter((answer) => { ? this.answersFromCms.filter((answer) => {
@ -78,11 +77,6 @@ export default {
isMobileOnly() { isMobileOnly() {
return this.isServiceableMobile && !this.isServiceableInshop; return this.isServiceableMobile && !this.isServiceableInshop;
}, },
isInshopOnly() {
return (
this.isServiceableInshop && !this.isServiceableMobile && !this.isServiceableDropoff
);
},
}, },
watch: { watch: {
answersToDisplay: { answersToDisplay: {
@ -92,7 +86,7 @@ export default {
newValue.length == 1 && newValue.length == 1 &&
newValue.findIndex((answer) => answer.Name == "Mobile") != -1 newValue.findIndex((answer) => answer.Name == "Mobile") != -1
) { ) {
this.selectedValue = "Mobile"; this.selectedValues = "Mobile";
} }
}, },
immediate: true, immediate: true,
@ -100,14 +94,7 @@ export default {
isMobileOnly: { isMobileOnly: {
handler(newValue) { handler(newValue) {
if (newValue) { if (newValue) {
this.selectedValue = "Mobile"; this.selectedValues = "Mobile";
}
},
},
isInshopOnly: {
handler(newValue) {
if (newValue) {
this.selectedValue = "Inshop";
} }
}, },
}, },

View file

@ -76,7 +76,6 @@
v-show="isAppointmentTypeDisplayed" v-show="isAppointmentTypeDisplayed"
:isServiceableMobile="isServiceableMobile" :isServiceableMobile="isServiceableMobile"
:isServiceableInshop="isServiceableInshop" :isServiceableInshop="isServiceableInshop"
:isServiceableDropoff="isServiceableDropoff"
:isDisplayed="isAppointmentTypeDisplayed" :isDisplayed="isAppointmentTypeDisplayed"
:mobileFeeApplies="mobileFeeApplies" :mobileFeeApplies="mobileFeeApplies"
ref="appointmentTypeQuestion" ref="appointmentTypeQuestion"
@ -197,8 +196,6 @@ export default {
isVehicleProtected: this.getIsVehicleProtectedFromStore(), isVehicleProtected: this.getIsVehicleProtectedFromStore(),
isGlassServiceableInshop: null, isGlassServiceableInshop: null,
isRecalibrationServiceableInshop: null, isRecalibrationServiceableInshop: null,
isGlassServiceableDropoff: null,
isRecalibrationServiceableDropoff: null,
isGlassServiceableMobile: null, isGlassServiceableMobile: null,
isRecalibrationServiceableMobile: null, isRecalibrationServiceableMobile: null,
selectedAppointmentType: this.getSelectedAppointmentType(), selectedAppointmentType: this.getSelectedAppointmentType(),
@ -357,13 +354,6 @@ export default {
return this.isGlassServiceableInshop; return this.isGlassServiceableInshop;
} }
}, },
isServiceableDropoff() {
if (this.isRecalibrationServiceableDropoff !== null) {
return this.isGlassServiceableDropoff && this.isRecalibrationServiceableDropoff;
} else {
return this.isGlassServiceableDropoff;
}
},
isShopQuestionDisplayed() { isShopQuestionDisplayed() {
return ( return (
this.selectedAppointmentType === "Inshop" || this.selectedAppointmentType === "Inshop" ||
@ -569,9 +559,6 @@ export default {
this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop; this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop;
this.isRecalibrationServiceableInshop = this.isRecalibrationServiceableInshop =
serviceabilityDetails.isRecalibrationServiceableInshop; serviceabilityDetails.isRecalibrationServiceableInshop;
this.isGlassServiceableDropoff = serviceabilityDetails.isGlassServiceableDropoff;
this.isRecalibrationServiceableDropoff =
serviceabilityDetails.isRecalibrationServiceableDropoff;
this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile; this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile;
this.isRecalibrationServiceableMobile = this.isRecalibrationServiceableMobile =
serviceabilityDetails.isRecalibrationServiceableMobile; serviceabilityDetails.isRecalibrationServiceableMobile;

View file

@ -415,33 +415,6 @@ describe("service-zip.vue", () => {
expect(wrapper.vm.displayInvalidZipAlert).toBe(false); expect(wrapper.vm.displayInvalidZipAlert).toBe(false);
expect(wrapper.vm.displayNonServiceableZipAlert).toBe(false); expect(wrapper.vm.displayNonServiceableZipAlert).toBe(false);
}); });
test("should show the AlertNoService when displayNoServiceAlert is true", async () => {
// Arrange
// no changes to store
applyMockStoreDataToGetters();
const wrapper = setupMocks({});
wrapper.vm.serviceZipCode = "12345";
// Act
wrapper.vm.displayNoServiceAlert = true;
// Check if the AlertNoService component is rendered
expect(wrapper.vm.displayNoServiceAlert).toBe(true);
});
test("should hide the AlertNoService when displayNoServiceAlert is false", async () => {
// Arrange
// no changes to store
applyMockStoreDataToGetters();
const wrapper = setupMocks({});
wrapper.vm.serviceZipCode = "12345";
//ACT
wrapper.vm.displayNoServiceAlert = false;
// Check if the AlertNoService component is rendered
expect(wrapper.vm.displayNoServiceAlert).toBe(false);
});
}); });
}); });
@ -538,16 +511,5 @@ function setupMocks({ customMountOptions, customZipQuery, customZipDataResponse
]; ];
const wrapper = shallowMount(serviceZip, mountOptions); const wrapper = shallowMount(serviceZip, mountOptions);
wrapper.vm.findClosestApplicableShops = jest.fn().mockImplementation(() => {
return Promise.resolve({
data: {
providers: [
{ id: 1, name: "Shop 1" },
{ id: 2, name: "Shop 2" },
],
},
});
});
return wrapper; return wrapper;
} }

View file

@ -47,18 +47,10 @@
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
alertClass="alert-danger" /> alertClass="alert-danger" />
<alert
ref="AlertNoService"
v-if="displayNoServiceAlert"
class="my-4"
cmsWidgetName="AlertNoServiceWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isForwardActionDisabled="!meta.valid || displayNoServiceAlert" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
@ -118,11 +110,8 @@ export default {
return { return {
serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode, serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode,
emailOrSms: this.getEmailOrSmsFromStore(), emailOrSms: this.getEmailOrSmsFromStore(),
carId: this.getCarIdfromStore(),
isHeavyTruck: this.getIsVehicleHeavyTruckFromStore(),
displayInvalidZipAlert: false, displayInvalidZipAlert: false,
displayNonServiceableZipAlert: false, displayNonServiceableZipAlert: false,
displayNoServiceAlert: false,
}; };
}, },
@ -195,19 +184,6 @@ export default {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
return store.getters.damage.isRepair || store.getters.damage.glassToReplace?.length > 0; return store.getters.damage.isRepair || store.getters.damage.glassToReplace?.length > 0;
}, },
getCarIdfromStore() {
return store.getters.vehicle.carId;
},
getIsVehicleHeavyTruckFromStore() {
return store.getters.isHeavyTruckVehicle;
},
async findClosestApplicableShops() {
return await this.dispatchStoreActionWithLogging(
storeActions.GET_CLOSEST_APPLICABLE_SHOPS,
{ zip: this.serviceZipCode, carId: this.carId },
"service-zip"
);
},
async backButtonAction() { async backButtonAction() {
const skipVin = await skipVinLookup(); const skipVin = await skipVinLookup();
// route to move backwards // route to move backwards
@ -276,16 +252,6 @@ export default {
return this.$refs.navbar.removeLoader(); return this.$refs.navbar.removeLoader();
} }
this.displayNonServiceableZipAlert = false; this.displayNonServiceableZipAlert = false;
if (this.isHeavyTruck) {
const closestShops = await this.findClosestApplicableShops(
this.serviceZipCode,
this.carId
);
this.displayNoServiceAlert = !closestShops?.data?.providers?.length;
if (this.displayNoServiceAlert) {
return this.$refs.navbar.removeLoader();
}
}
const payment = this.$store.getters.payment; const payment = this.$store.getters.payment;
const policy = this.$store.getters.policy; const policy = this.$store.getters.policy;
@ -343,7 +309,6 @@ export default {
watch: { watch: {
serviceZipCode() { serviceZipCode() {
this.displayNonServiceableZipAlert = false; this.displayNonServiceableZipAlert = false;
this.displayNoServiceAlert = false;
}, },
}, },
components: { components: {

View file

@ -258,39 +258,6 @@ describe("vin-lookup.vue", () => {
// Assert // Assert
expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(1); expect(wrapper.findAllComponents({ name: "alert" }).length).toBe(1);
}); });
test("should show the AlertNoService when displayNoServiceAlert is true", async () => {
const { wrapper } = setupMocks({
isZipServiceable: true,
displayNoServiceAlert: true,
lookupVinbyAddressResponse: {
isStatePermissible: true,
vinVehicles: [], // Return no vehicles
},
});
// Set displayNoServiceAlert to true
await wrapper.setData({ displayNoServiceAlert: true });
// Check if the AlertNoService component is rendered
const alertNoService = wrapper.findComponent({ ref: "AlertNoService" });
expect(alertNoService.exists()).toBe(true);
});
test("should hide the AlertNoService when displayNoServiceAlert is false", async () => {
const { wrapper } = setupMocks({
isZipServiceable: true,
displayNoServiceAlert: false,
lookupVinbyAddressResponse: {
isStatePermissible: true,
vinVehicles: [], // Return no vehicles
},
});
// Ensure displayNoServiceAlert is false
await wrapper.setData({ displayNoServiceAlert: false });
// Check if the AlertNoService component is not rendered
const alertNoService = wrapper.findComponent({ ref: "AlertNoService" });
expect(alertNoService.exists()).toBe(false);
});
}); });
describe("getVinFromImage", () => { describe("getVinFromImage", () => {

View file

@ -71,8 +71,7 @@
vinPopulatedOnPageLoad && vinPopulatedOnPageLoad &&
isInsuranceVerified && isInsuranceVerified &&
!displayInvalidZipAlert && !displayInvalidZipAlert &&
!displayNonServiceableZipAlert && !displayNonServiceableZipAlert
!displayNoServiceAlert
" "
alertClass="alert-success" /> alertClass="alert-success" />
@ -108,23 +107,14 @@
vinPopulatedOnPageLoad && vinPopulatedOnPageLoad &&
!isInsuranceVerified && !isInsuranceVerified &&
!displayInvalidZipAlert && !displayInvalidZipAlert &&
!displayNonServiceableZipAlert && !displayNonServiceableZipAlert
!displayNoServiceAlert
" "
alertClass="alert-success" /> alertClass="alert-success" />
<alert
ref="AlertNoService"
v-if="displayNoServiceAlert"
class="my-4"
cmsWidgetName="AlertNoServiceWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isForwardActionDisabled="!meta.valid || displayNoServiceAlert" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
@ -207,8 +197,6 @@ export default {
vin: this.getVinFromStore(), vin: this.getVinFromStore(),
serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode, serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode,
emailOrSms: this.getEmailOrSmsFromStore(), emailOrSms: this.getEmailOrSmsFromStore(),
carId: this.getCarIdfromStore(),
isHeavyTruck: this.getIsVehicleHeavyTruckFromStore(),
isCarIdDifferent: false, isCarIdDifferent: false,
customAlertData: {}, customAlertData: {},
previouslyEnteredCarId: "", previouslyEnteredCarId: "",
@ -219,7 +207,6 @@ export default {
displayVinNotFoundAlert: false, displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false, displayMatchedDifferentVehicleAlert: false,
displayVinScanFailedAlert: false, displayVinScanFailedAlert: false,
displayNoServiceAlert: false,
}; };
}, },
methods: { methods: {
@ -235,12 +222,6 @@ export default {
getZipFromStore() { getZipFromStore() {
return this.$store.getters.order.serviceLocation.zipCode; return this.$store.getters.order.serviceLocation.zipCode;
}, },
getCarIdfromStore() {
return store.getters.vehicle.carId;
},
getIsVehicleHeavyTruckFromStore() {
return store.getters.isHeavyTruckVehicle;
},
attachCustomEvents() { attachCustomEvents() {
this.prependActionToMethod(this, this.forwardButtonAction, () => { this.prependActionToMethod(this, this.forwardButtonAction, () => {
this.pushEventToGA( this.pushEventToGA(
@ -264,13 +245,6 @@ export default {
); );
} }
}, },
async findClosestApplicableShops() {
return await this.dispatchStoreActionWithLogging(
storeActions.GET_CLOSEST_APPLICABLE_SHOPS,
{ zip: this.serviceZipCode, carId: this.carId },
"vin-lookup"
);
},
async forwardButtonAction() { async forwardButtonAction() {
this.resetAlerts(); this.resetAlerts();
@ -303,18 +277,6 @@ export default {
return this.$refs.navbar.removeLoader(); return this.$refs.navbar.removeLoader();
} }
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
if (this.isHeavyTruck) {
// If a VIN has already been found. Validate the Service Zip (in case of changes)
var closestShops = await this.findClosestApplicableShops(
this.serviceZipCode,
this.carId
);
this.displayNoServiceAlert = !closestShops?.data?.providers?.length;
if (this.displayNoServiceAlert) {
return this.$refs.navbar.removeLoader();
}
}
// If either lookup fails, remove the loader and stop processing the page. // If either lookup fails, remove the loader and stop processing the page.
if (!resultMap.vehicleLookupResponse || !resultMap.zipCodeData.isServiceable) { if (!resultMap.vehicleLookupResponse || !resultMap.zipCodeData.isServiceable) {
// If the vehicle result is undefined, the vin entered was invalid. // If the vehicle result is undefined, the vin entered was invalid.
@ -431,16 +393,6 @@ export default {
); );
} }
closestShops = await this.findClosestApplicableShops(
this.serviceZipCode,
this.carId
);
this.displayNoServiceAlert = !closestShops?.data?.providers?.length;
if (this.displayNoServiceAlert) {
return this.$refs.navbar.removeLoader();
}
// if no value due to field being optional, blank both phone and email address
if (!this.emailOrSms) { if (!this.emailOrSms) {
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false); await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false); await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false);
@ -522,7 +474,6 @@ export default {
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
this.displayVinNotFoundAlert = false; this.displayVinNotFoundAlert = false;
this.displayVinScanFailedAlert = false; this.displayVinScanFailedAlert = false;
this.displayNoServiceAlert = false;
}, },
}, },
mounted() { mounted() {
@ -599,7 +550,6 @@ export default {
}, },
serviceZipCode() { serviceZipCode() {
this.displayNonServiceableZipAlert = false; this.displayNonServiceableZipAlert = false;
this.displayNoServiceAlert = false;
}, },
}, },
components: { components: {