Merge branch 'develop' into defect/CSR-1467
This commit is contained in:
commit
8a119e89f4
10 changed files with 18988 additions and 36 deletions
18896
src/constants/single-windshield-carids.js
Normal file
18896
src/constants/single-windshield-carids.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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}`,
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue