diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 2cb18429c..3867fdcd6 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -18,9 +18,11 @@ pr:
resources:
containers:
- container: node
- image: packagerepository.sagaws.net:8082/safelite/node-build:18
+ image: ghcr.io/safelite/node-build:18
+ endpoint: GitHub Docker
- container: awscli
- image: packagerepository.sagaws.net:8082/safelite/awscli2-build:3.9
+ image: ghcr.io/safelite/awscli2-build:3.9
+ endpoint: GitHub Docker
- container: prettier-node
image: ghcr.io/safelite/prettier-node-build:23
endpoint: GitHub Docker
diff --git a/jest.config.js b/jest.config.js
index e534b3e3f..70916274f 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -4,6 +4,9 @@ module.exports = {
testResultsProcessor: "jest-junit",
preset: "@vue/cli-plugin-unit-jest",
transform: { "^.+\\.vue$": "@vue/vue3-jest" },
+ transformIgnorePatterns: [
+ '/node_modules/(?!.*\\.mjs$)',
+ ],
moduleFileExtensions: ["js", "vue"],
modulePathIgnorePatterns: ["vin-lookup"],
collectCoverageFrom: [
diff --git a/src/digital-components/salesforce-webchat/salesforce-webchat.spec.js b/src/digital-components/salesforce-webchat/salesforce-webchat.spec.js
index 178e431cc..40fc752fd 100644
--- a/src/digital-components/salesforce-webchat/salesforce-webchat.spec.js
+++ b/src/digital-components/salesforce-webchat/salesforce-webchat.spec.js
@@ -3,6 +3,7 @@ import salesforceWebchat from "./salesforce-webchat.vue";
import * as devHelper from "./salesforce-helper-dev";
import * as qaHelper from "./salesforce-helper-qa";
import * as prodHelper from "./salesforce-helper-prod";
+import { applicationConfig } from "../../constants/application-config";
describe("salesforceWebchat.vue", () => {
it("renders correctly", () => {
@@ -21,19 +22,19 @@ describe("salesforceWebchat.vue", () => {
});
it("calls the correct initialization function based on environment", () => {
- process.env.VUE_APP_CURRENT_ENVIRONMENT = "Prod";
+ applicationConfig.CURRENT_ENVIRONMENT = "Prod";
let wrapper = shallowMount(salesforceWebchat);
mockProd = jest.spyOn(prodHelper, "initializeSalesforceWebchatForProd");
wrapper.vm.initializeSalesforceWebchat();
expect(mockProd).toHaveBeenCalled();
- process.env.VUE_APP_CURRENT_ENVIRONMENT = "QA";
+ applicationConfig.CURRENT_ENVIRONMENT = "QA";
wrapper = shallowMount(salesforceWebchat);
mockQa = jest.spyOn(qaHelper, "initializeSalesforceWebchatForQa");
wrapper.vm.initializeSalesforceWebchat();
expect(mockQa).toHaveBeenCalled();
- process.env.VUE_APP_CURRENT_ENVIRONMENT = "Dev";
+ applicationConfig.CURRENT_ENVIRONMENT = "Dev";
wrapper = shallowMount(salesforceWebchat);
mockDev = jest.spyOn(devHelper, "initializeSalesforceWebchatForDev");
wrapper.vm.initializeSalesforceWebchat();
diff --git a/src/digital-components/salesforce-webchat/salesforce-webchat.vue b/src/digital-components/salesforce-webchat/salesforce-webchat.vue
index 75f689d10..9283bda62 100644
--- a/src/digital-components/salesforce-webchat/salesforce-webchat.vue
+++ b/src/digital-components/salesforce-webchat/salesforce-webchat.vue
@@ -7,6 +7,7 @@
import { initializeSalesforceWebchatForDev } from "./salesforce-helper-dev";
import { initializeSalesforceWebchatForQa } from "./salesforce-helper-qa";
import { initializeSalesforceWebchatForProd } from "./salesforce-helper-prod";
+import { applicationConfig } from "@/constants/application-config";
export default {
name: "salesforceWebchat",
@@ -28,7 +29,7 @@ export default {
},
methods: {
initializeSalesforceWebchat() {
- switch (process.env.VUE_APP_CURRENT_ENVIRONMENT) {
+ switch (applicationConfig.CURRENT_ENVIRONMENT) {
case "Prod":
initializeSalesforceWebchatForProd();
break;
diff --git a/src/layouts/address-lookup/address-lookup.spec.js b/src/layouts/address-lookup/address-lookup.spec.js
index 677c14069..87486280f 100644
--- a/src/layouts/address-lookup/address-lookup.spec.js
+++ b/src/layouts/address-lookup/address-lookup.spec.js
@@ -182,6 +182,23 @@ describe("address-lookup.vue", () => {
// Assert
expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).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 });
+ await wrapper.vm.forwardButtonAction();
+ // Check if the AlertNoService component is not rendered
+ const alertNoService = wrapper.findComponent({ ref: "AlertNoService" });
+ expect(alertNoService.exists()).toBe(false);
+ });
});
describe("navigation", () => {
@@ -741,6 +758,17 @@ function setupMocks({
wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.$refs.navbar.updateButtonText = 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 };
}
diff --git a/src/layouts/address-lookup/address-lookup.vue b/src/layouts/address-lookup/address-lookup.vue
index ba2f8f6dd..d0cca48d9 100644
--- a/src/layouts/address-lookup/address-lookup.vue
+++ b/src/layouts/address-lookup/address-lookup.vue
@@ -81,13 +81,20 @@
+
+ :isForwardActionDisabled="!meta.valid || displayNoServiceAlert" />
@@ -177,6 +184,7 @@ export default {
displayInvalidZipAlert: false,
showServiceZipField: this.getServiceZipFromStore(),
isZipServiceable: false,
+ displayNoServiceAlert: false,
};
},
methods: {
@@ -293,6 +301,17 @@ export default {
return this.$refs.navbar.removeLoader();
}
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;
// Handle cases for different amounts of VINS found for the address.
@@ -444,6 +463,7 @@ export default {
this.displayNonServiceableZipAlert = false;
this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
+ this.displayNoServiceAlert = false;
},
},
mounted() {
@@ -495,6 +515,7 @@ export default {
handler(newValue) {
// If they modify the service zip code, then hide the error message.
this.displayNonServiceableZipAlert = false;
+ this.displayNoServiceAlert = false;
},
},
showServiceZipField: {
diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js
index 14f0408d1..a1b768fb3 100644
--- a/src/layouts/license-plate-lookup/license-plate-lookup.spec.js
+++ b/src/layouts/license-plate-lookup/license-plate-lookup.spec.js
@@ -620,6 +620,8 @@ function setupMocks({
validateZipResponse = { zipCodeCtu: null, isServiceable: false, isValid: true, state: null },
//Values to set in the state store
carId = null,
+ isHeavyTruck = true,
+ displayNoServiceAlert = true,
serviceLocationZipCode = null,
registrationZipCode = null,
licensePlate = null, //"TESTPLATE",
@@ -672,6 +674,8 @@ function setupMocks({
zipCode: registrationZipCode,
},
carId: carId,
+ isBigTruck: isHeavyTruck,
+ canSafeliteService: true,
},
order: {
customer: {
@@ -716,5 +720,17 @@ function setupMocks({
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
wrapper.vm.$refs.navbar.updateButtonText = 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 };
}
diff --git a/src/layouts/license-plate-lookup/license-plate-lookup.vue b/src/layouts/license-plate-lookup/license-plate-lookup.vue
index 8736df956..223ca9ee7 100644
--- a/src/layouts/license-plate-lookup/license-plate-lookup.vue
+++ b/src/layouts/license-plate-lookup/license-plate-lookup.vue
@@ -76,6 +76,7 @@
:manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning"
v-bind:isDismissible="false" />
+
+ @ForwardClicked="forwardButtonAction" />
@@ -177,6 +178,7 @@ export default {
displayInvalidZipAlert: false,
showServiceZipField: this.getServiceZipFromStore(),
isZipServiceable: false,
+ displayNoServiceAlert: false,
};
},
methods: {
@@ -279,6 +281,17 @@ export default {
this.displayInvalidZipAlert = true;
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.
this.isCarIdDifferent =
vinLookup.data.vehicle.carId !== this.$store.getters.vehicle.carId;
@@ -393,6 +406,7 @@ export default {
this.displayMatchedDifferentVehicleAlert = false;
this.displayVinLookupByHomeAddressNotAllowedAlert = false;
this.displayInvalidZipAlert = false;
+ this.displayNoServiceAlert = false;
},
},
mounted() {
@@ -437,6 +451,7 @@ export default {
serviceZipCode() {
// If they modify the service zip code, then hide the error message.
this.displayNonServiceableZipAlert = false;
+ this.displayNoServiceAlert = false;
this.$refs.navbar.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
);
diff --git a/src/layouts/payment-method/afterpay-breakout/afterpay-breakout.vue b/src/layouts/payment-method/afterpay-breakout/afterpay-breakout.vue
index 06a717289..0e1e3d58a 100644
--- a/src/layouts/payment-method/afterpay-breakout/afterpay-breakout.vue
+++ b/src/layouts/payment-method/afterpay-breakout/afterpay-breakout.vue
@@ -3,18 +3,16 @@
-
{{ this.afterpayPrice }}
-
-
![]()
-
+
+ data-bind="click:afterpayLearnMore"
+ class="afterpay-learn-more">
@@ -151,8 +149,8 @@ export default {
&.alert-info {
.alert-heading {
- color: #000000;
- font-weight: 600;
+ color: $black;
+ font-weight: $font-weight-600;
margin-left: 0.5rem;
margin-right: 0.5rem;
@include media-breakpoint-up(md) {
@@ -162,11 +160,12 @@ export default {
}
}
.afterpay-amount {
- color: #0c7e47;
+ color: $green;
+ margin-left: 0.25rem;
}
.alert-sub-heading {
- color: #4b4c4e;
- font-weight: 400;
+ color: $gray-1100;
+ font-weight: $font-weight-normal;
}
.after-pay {
.after-pay-toggle {
@@ -180,7 +179,7 @@ export default {
background-position: right center;
margin-left: 0.5rem;
width: 1rem;
- height: 9px;
+ height: 0.5625rem;
display: inline-flex;
}
&.expanded:after {
@@ -194,8 +193,8 @@ export default {
}
}
.after-pay-toggle a {
- font-weight: 600;
- color: #0070d1;
+ font-weight: $font-weight-600;
+ color: $blue;
text-decoration: none;
}
.after-pay-details {
@@ -218,27 +217,45 @@ export default {
.payment-card {
display: flex;
flex-direction: column;
- border-radius: 6px;
- border: 0.25px #b3b4b5;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+ border-radius: 0.375rem;
+ border: 0.25px $gray-1000;
+ box-shadow: 0px 4px 8px -4px rgba(0, 0, 0, 0.15);
}
.calendar-section {
- background-color: #fff; /* White background for calendar area */
+ background-color: $white; /* White background for calendar area */
padding: 0.5rem;
text-align: center;
- gap: 2px;
- font-weight: 700;
+ gap: 0.125rem;
+ font-weight: $font-weight-700;
white-space: nowrap;
+ border-top-left-radius: 0.375rem;
+ border-top-right-radius: 0.375rem;
+ width: 4.375rem;
+ @include media-breakpoint-up(md) {
+ width: 5rem;
+ }
}
.payment-amount-section {
- background-color: #e0f7e9; /* Light green background for payment area */
+ background-color: $green-600; /* Light green background for payment area */
padding: 0.5rem;
text-align: center;
- font-weight: 700;
+ font-weight: $font-weight-700;
+ border-bottom-left-radius: 0.375rem;
+ border-bottom-right-radius: 0.375rem;
+ width: 4.375rem;
+ @include media-breakpoint-up(md) {
+ width: 5rem;
+ }
+ }
+ .afterpay-learn-more {
+ margin-left: 0.25rem;
+ }
+ .afterpay-image {
+ margin-left: 0.25rem;
}
.amount-due {
- color: #00723e; /* Green text */
+ color: $green-1000; /* Green text */
}
.legend {
display: flex;
@@ -249,11 +266,11 @@ export default {
.legend-item {
display: flex;
align-items: center;
- gap: 2px;
+ gap: 0.125rem;
white-space: nowrap;
}
.legend-item span {
- font-weight: 400;
+ font-weight: $font-weight-normal;
}
}
diff --git a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
index 0d7a82248..ac597c72b 100644
--- a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
+++ b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
@@ -1,72 +1,70 @@
-
-
-
-
-
-
-
-
-
- {{ errorMessage }}
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+ {{ errorMessage }}
+
+
+
-
+
+
+
+
+
+
+
+
+
+