Merge branch 'develop' into defect/CSR-1467

This commit is contained in:
Leah Schumann 2023-06-28 08:25:38 -04:00
commit 8a119e89f4
10 changed files with 18988 additions and 36 deletions

File diff suppressed because it is too large Load diff

View file

@ -17,18 +17,12 @@ export default {
additionalSuccessEventDataHandler, additionalSuccessEventDataHandler,
}) { }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO; const cfDistroUrl = applicationConfig.CONSUMER_CF_DISTRO;
const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" }); const payloadAndAnalyticsData = Object.assign({}, payload, { AppName: "FixMyGlass" });
const headers = { const headers = {
[headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings), [headerKeys.EXPERIMENT]: JSON.stringify(store.getters.experimentSettings),
}; };
if (endpoint.toLowerCase().includes("/analytics/")) {
cfDistroUrl = "";
endpoint = "";
method = "GET";
}
axios({ axios({
method: method, method: method,
url: cfDistroUrl + endpoint, url: cfDistroUrl + endpoint,
@ -44,7 +38,7 @@ export default {
additionalEventData = "_" + additionalSuccessEventDataHandler(response); additionalEventData = "_" + additionalSuccessEventDataHandler(response);
} }
const pageName = analyticsMixIn.methods.getPageName(); const pageName = analyticsMixIn.methods.getPageName();
const nextPageName = router.getNextPage() || pageName; const nextPageName = router.lastNavigationPage || pageName;
analyticsMixIn.methods.pushEventToGA( analyticsMixIn.methods.pushEventToGA(
GaCategories.API_RESPONSE, GaCategories.API_RESPONSE,
`${nextPageName}_${endpoint}`, `${nextPageName}_${endpoint}`,

View file

@ -27,7 +27,7 @@
v-model="customerModel.emailAddress" v-model="customerModel.emailAddress"
ref="emailAddress" ref="emailAddress"
customInputId="emailAddress" customInputId="emailAddress"
validationRules="email-address-required|email-address-format" /> validationRules="email-address-format" />
</div> </div>
</div> </div>
<div class="row mb-4"> <div class="row mb-4">
@ -49,7 +49,6 @@ import textBlock from "@/digital-components/text-block/text-block";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("first-name-required", required(errorMessages.FIRST_NAME_REQUIRED)); defineRule("first-name-required", required(errorMessages.FIRST_NAME_REQUIRED));
defineRule("last-name-required", required(errorMessages.LAST_NAME_REQUIRED)); defineRule("last-name-required", required(errorMessages.LAST_NAME_REQUIRED));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule( defineRule(
"email-address-format", "email-address-format",
regex( regex(

View file

@ -151,7 +151,6 @@ export default {
if ( if (
store.getters.order.vehicle.carId && store.getters.order.vehicle.carId &&
store.getters.order.serviceLocation.zipCode && store.getters.order.serviceLocation.zipCode &&
store.getters.order.customer.emailAddress &&
store.getters.pageData(fmgPageValues.ADDRESS_VEHICLES) store.getters.pageData(fmgPageValues.ADDRESS_VEHICLES)
) { ) {
return true; return true;

View file

@ -44,8 +44,8 @@
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="emailAddress" v-model="emailAddress"
inputId="emailAddress" inputId="emailAddress"
isRequired disableAutoFill
validationRules="email-address-required|email-address-format" /> validationRules="email-address-format" />
</div> </div>
</div> </div>
<div class="row mb-2"> <div class="row mb-2">
@ -117,7 +117,6 @@ import { queryStrings } from "@/constants/query-strings";
// Define Validation Rules // Define Validation Rules
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)); defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule( defineRule(
"email-address-format", "email-address-format",
regex( regex(

View file

@ -24,7 +24,7 @@
v-model="registrationZipCode" v-model="registrationZipCode"
customInputId="zip" customInputId="zip"
mask="#####" mask="#####"
validationRules="zip-required|zip-format" /> validationRules="registration-zip-required|zip-format" />
</div> </div>
</div> </div>
<div class="row mt-0"> <div class="row mt-0">
@ -33,7 +33,7 @@
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="email" v-model="email"
customInputId="email" customInputId="email"
validationRules="email-address-required|email-address-format" /> validationRules="email-address-format" />
</div> </div>
</div> </div>
<div class="row mb-2"> <div class="row mb-2">
@ -114,9 +114,8 @@ import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED)); defineRule("license-plate-required", required(errorMessages.LICENSE_PLATE_REQUIRED));
defineRule("zip-required", required(errorMessages.REGISTRATION_ZIP_REQUIRED)); defineRule("registration-zip-required", required(errorMessages.REGISTRATION_ZIP_REQUIRED));
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)); defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule( defineRule(
"email-address-format", "email-address-format",
regex( regex(

View file

@ -59,7 +59,7 @@
v-model="emailAddress" v-model="emailAddress"
customInputId="emailAddress" customInputId="emailAddress"
isRequired isRequired
validationRules="email-address-required|email-address-format" /> validationRules="email-address-format" />
</div> </div>
</div> </div>
<div class="row mb-2"> <div class="row mb-2">
@ -152,7 +152,6 @@ import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES // DEFINE VALIDATION RULES
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)); defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule( defineRule(
"email-address-format", "email-address-format",
regex( regex(

View file

@ -156,6 +156,14 @@ const router = createRouter({
//---------------------------------------------------------- Router Functions ---------------------------------------------------------- //---------------------------------------------------------- Router Functions ----------------------------------------------------------
router.beforeEach(async (to, from, next) => {
// set lastNavigationPage here to capture state before API calls for analytics.
// use current page url query string name when to.name is "root" (due to unresolved navigation in beforeEach)
router.lastNavigationPage = to.name == "root" ? analyticsMixin.methods.getPageName() : to.name;
next();
});
router.afterEach(async (to, from) => { router.afterEach(async (to, from) => {
// Update lastPageVisited in the store // Update lastPageVisited in the store
store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name); store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name);

View file

@ -8,6 +8,7 @@ import { storeActions } from "@/constants/store-actions";
import { applicationConfig } from "@/constants/application-config"; import { applicationConfig } from "@/constants/application-config";
import { experimentTriggers } from "@/constants/experiments"; import { experimentTriggers } from "@/constants/experiments";
import { damageLocationsSelected } from "@/constants/damage-locations-selected"; import { damageLocationsSelected } from "@/constants/damage-locations-selected";
import { singleWindshieldCarIds } from "@/constants/single-windshield-carids";
import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js"; import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper.js";
import { deepEqual } from "@/helpers/object-helper"; import { deepEqual } from "@/helpers/object-helper";
@ -642,13 +643,28 @@ export const actions = {
}, },
lookupVinByImage(context, image) { lookupVinByImage(context, image) {
const data = new FormData(); return new Promise((resolve, reject) => {
data.append("vinImage", image); let reader = new FileReader();
return globalMethods.callHttpClient({ reader.onload = (e) => {
method: endpoints.LookupVinByImage.method, resolve(reader.result);
endpoint: endpoints.LookupVinByImage.url, };
payload: data, reader.readAsDataURL(image);
isFormData: true, }).then((result) => {
const components = result.split(",");
const contentType = image.type;
const imageBase64 = components[1];
const data = {
imageData: imageBase64,
contentType: contentType,
fileName: image.name,
};
return globalMethods.callHttpClient({
method: endpoints.LookupVinByImage.method,
endpoint: endpoints.LookupVinByImage.url,
payload: data,
});
}); });
}, },
@ -1346,7 +1362,7 @@ export const actions = {
}, },
}, },
customer: { customer: {
emailAddress: order.customer.emailAddress, emailAddress: order.customer.emailAddress || null,
}, },
damage: { damage: {
numberOfChips: damage.numberOfChips, numberOfChips: damage.numberOfChips,
@ -1943,6 +1959,19 @@ export const actions = {
}, },
isVinOptionalVehicle(context) { isVinOptionalVehicle(context) {
//Optional for carIds with only a single windshield
if (
singleWindshieldCarIds.find((item) => item === context.state.order.vehicle.carId) &&
context.state.order.damage.glassToReplace.length == 1 &&
context.state.order.damage.glassToReplace.find(
(glassToReplace) =>
glassToReplace.glassLocation.toLowerCase() ===
damageLocationsSelected.WINDSHIELD.toLowerCase()
)
) {
return true;
}
//Optional for specific YMMSs
switch (context.state.order.vehicle.make.toLowerCase()) { switch (context.state.order.vehicle.make.toLowerCase()) {
case "mercedes benz": case "mercedes benz":
case "volkswagen": case "volkswagen":
@ -1951,14 +1980,12 @@ export const actions = {
return true; return true;
default: default:
} }
if ( if (
context.state.order.vehicle.make.toLowerCase() === "ford" && context.state.order.vehicle.make.toLowerCase() === "ford" &&
context.state.order.vehicle.year >= 2018 context.state.order.vehicle.year >= 2018
) { ) {
return true; return true;
} }
if ( if (
context.state.order.vehicle.make.toLowerCase() === "bmw" && context.state.order.vehicle.make.toLowerCase() === "bmw" &&
context.state.order.vehicle.year <= 2017 context.state.order.vehicle.year <= 2017

View file

@ -406,14 +406,16 @@ describe("Actions", () => {
it("lookupVinByImage action, should return list of vins", async () => { it("lookupVinByImage action, should return list of vins", async () => {
// Arrange // Arrange
const context = state; const context = state;
const dummyImage = {}; const image = new File([], "test.jpg", {
type: "image/jpeg",
});
globalMethods.callHttpClient.mockImplementation(() => { globalMethods.callHttpClient.mockImplementation(() => {
return Promise.resolve({ data: ["1C6JJTAG3NL134044"] }); return Promise.resolve({ data: ["1C6JJTAG3NL134044"] });
}); });
// Act // Act
const response = await actions.lookupVinByImage(context, dummyImage); const response = await actions.lookupVinByImage(context, image);
// Assert // Assert
expect(response.data).toEqual(["1C6JJTAG3NL134044"]); expect(response.data).toEqual(["1C6JJTAG3NL134044"]);
@ -422,7 +424,9 @@ describe("Actions", () => {
it("lookupVinByImage action, should reject if error in calling API", async () => { it("lookupVinByImage action, should reject if error in calling API", async () => {
// Arrange // Arrange
const context = state; const context = state;
const dummyImage = {}; const image = new File([], "test.jpg", {
type: "image/jpeg",
});
globalMethods.callHttpClient.mockImplementation(() => { globalMethods.callHttpClient.mockImplementation(() => {
return Promise.reject("An error occurred"); return Promise.reject("An error occurred");
@ -431,9 +435,7 @@ describe("Actions", () => {
// Act // Act
// Assert // Assert
await expect(actions.lookupVinByImage(context, dummyImage)).rejects.toEqual( await expect(actions.lookupVinByImage(context, image)).rejects.toEqual("An error occurred");
"An error occurred"
);
}); });
it("getVehicleMakes action, should return makes list", async () => { it("getVehicleMakes action, should return makes list", async () => {
@ -3209,6 +3211,36 @@ describe("isVinOptionalVehicle", () => {
}, },
}; };
var vinOptionalResult = actions.isVinOptionalVehicle(context);
expect(vinOptionalResult).toEqual(expectedVinSkip);
}
);
const testcarID = [
["CR00000100", "make", [{ glassLocation: "driver" }], false],
["CR00067899", "make2", [{ glassLocation: "windshield" }], true],
[
"CR00062396",
"make3",
[{ glassLocation: "windshield" }, { glassLocation: "driver" }],
false,
],
["CR00066428", "make4", [{ glassLocation: "rear" }], false],
];
test.each(testcarID)(
"%s %s %o should skip vin lookup is %s",
async (carId, make, glassLocation, expectedVinSkip) => {
const context = state;
context.state = {
order: {
vehicle: { make: make, carId: carId },
damage: {
glassToReplace: glassLocation,
},
},
};
var vinOptionalResult = actions.isVinOptionalVehicle(context); var vinOptionalResult = actions.isVinOptionalVehicle(context);
expect(vinOptionalResult).toEqual(expectedVinSkip); expect(vinOptionalResult).toEqual(expectedVinSkip);
} }