Merge pull request #1800 from Safelite/feature/csr-1984

Feature/csr 1984 + Partial 2027
This commit is contained in:
chloeherdsafelite 2024-03-12 16:43:29 -04:00 committed by GitHub
commit 2916da90c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 501 additions and 312 deletions

View file

@ -49,6 +49,7 @@ const storeMutations = {
UPDATE_BILL_TO_ACCT_NUMBER: "updateBillToAcctNumber", UPDATE_BILL_TO_ACCT_NUMBER: "updateBillToAcctNumber",
UPDATE_EON: "updateEON", UPDATE_EON: "updateEON",
UPDATE_IS_INSURANCE: "updateIsInsurance", UPDATE_IS_INSURANCE: "updateIsInsurance",
UPDATE_IS_VERIFIED_INSURANCE: "updateInsuranceVerifiedStatus",
UPDATE_SAVED_SESSION_ID: "updateSavedSessionId", UPDATE_SAVED_SESSION_ID: "updateSavedSessionId",
UPDATE_CRM_CUSTOMER_ID: "updateCrmCustomerId", UPDATE_CRM_CUSTOMER_ID: "updateCrmCustomerId",
UPDATE_IS_PIA: "updateIsPia", UPDATE_IS_PIA: "updateIsPia",

View file

@ -12,38 +12,87 @@ import { includesWindshieldReplacement } from "@/helpers/damage-helper";
import store from "@/store"; import store from "@/store";
import router from "@/router"; import router from "@/router";
/*
If the user has visited the funnel before this method will determine the bets place to
drop them so they don't start at the beginning again. This method will return 'heritage' if
the user has an existing order and they come back in from the Safelite.com CTA.
*/
export async function getPageToRouteExistingOrderTo(toRoute = {}) { export async function getPageToRouteExistingOrderTo(toRoute = {}) {
const fmgPage = getQuerystringParameter(queryStrings.FMG_PAGE.toLowerCase()); const fmgQueryPage = toRoute.query[queryStrings.FMG_PAGE];
if (fmgPage && fmgPage === fmgPageValues.SERVICE_LOCATION) { const hasFmgQueryPage = !!fmgQueryPage;
const serviceLocationComponent = await getLazyLoadedComponent(
fmgPageValues.SERVICE_LOCATION if (hasFmgQueryPage) {
return await getDirectNavigation(toRoute);
} else {
return await getImplicitNavigation(toRoute);
}
}
/*
* Send the user to the specified page, except in specific scenarios.
*/
export async function getDirectNavigation(toRoute) {
const fmgPageValue = toRoute.query[queryStrings.FMG_PAGE];
// Verified insurance users need to be routed around some pages
// vehicle -> vehicle-damage
// quote -> heritage
// insurance-company -> heritage
if (store.getters.payment.insuranceCoverage.isVerified) {
if (fmgPageValue === fmgPageValues.VEHICLE) {
return fmgPageValues.VEHICLE_DAMAGE;
}
if (
fmgPageValue === fmgPageValues.QUOTE ||
fmgPageValue === fmgPageValues.INSURANCE_COMPANY
) {
return fmgPageValues.HERITAGE;
}
}
// Otherwise, respect navigation from query string.
return fmgPageValue;
}
/*
* Determine which page in the flow the user should be sent to, based on their current order.
* General strategy: run through pages in reverse order, and select first where prerequisites are valid.
* QUOTE is the latest page to send to.
*/
export async function getImplicitNavigation(toRoute) {
const vehicleDamageComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_DAMAGE);
const estimateComponent = await getLazyLoadedComponent(fmgPageValues.ESTIMATE);
const vinLookupComponent = await getLazyLoadedComponent(fmgPageValues.VIN_LOOKUP);
const partQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.PART_QUESTIONS);
const vehiclePartsComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_PARTS);
const moldingQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.MOLDING_QUESTIONS);
const capabilityQuestionsComponent = await getLazyLoadedComponent(
fmgPageValues.CAPABILITY_QUESTIONS
); );
if (serviceLocationComponent.methods.arePagePrerequisitesValid()) { const quoteComponent = await getLazyLoadedComponent(fmgPageValues.QUOTE);
return fmgPageValues.SERVICE_LOCATION;
}
}
// If the user is coming in via the Safelite.Com CTA const skipVin = await skipVinLookup();
if (toRoute.query[queryStrings.START_TYPE] === "fmg") {
const latestPageRoute = await getLatestPageForRedirection();
return latestPageRoute;
}
// If navigating to a specific page, and that page is not part of the vin pages. if (quoteComponent.methods.arePagePrerequisitesValid()) {
// Return that page, so that it can navigate like normal. // Do not send to quote if verified insurance user.
if (toRoute.query[queryStrings.FMG_PAGE] !== undefined && !isVinRelatedPage(toRoute)) { if (store.getters.payment.insuranceCoverage.isVerified) {
return overrideYmmsDirectionIfNeeded(toRoute); return fmgPageValues.HERITAGE;
} else {
return fmgPageValues.QUOTE;
}
} else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.CAPABILITY_QUESTIONS;
} else if (moldingQuestionsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.MOLDING_QUESTIONS;
} else if (vehiclePartsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.VEHICLE_PARTS;
} else if (partQuestionsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.PART_QUESTIONS;
} else if (vinLookupComponent.methods.arePagePrerequisitesValid() && !skipVin) {
return fmgPageValues.VIN_LOOKUP;
} else if (estimateComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.ESTIMATE;
} else if (vehicleDamageComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.VEHICLE_DAMAGE;
} else {
return fmgPageValues.VEHICLE;
} }
// If this is not a direct link to a page using fmgPage, not from Safelite.com CTA or this is a vin related page.
// Get the latest page for redirection.
const latestPageRoute = await getLatestPageForRedirection();
return latestPageRoute;
} }
/* /*
@ -114,96 +163,6 @@ export async function skipVinLookupNotRepair() {
); );
} }
/*
Logic for getting the last "valid" page a user visited.
*/
async function getLatestPageForRedirection() {
// If this is a non-CTA navigation, determine where to send the user based on page prerequisites.
// This also works if a user has a 'fmg' start_type query string but no current order.
// That shouldn't happen, but it's possible.
const vehicleDamageComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_DAMAGE);
const estimateComponent = await getLazyLoadedComponent(fmgPageValues.ESTIMATE);
const vinLookupComponent = await getLazyLoadedComponent(fmgPageValues.VIN_LOOKUP);
const partQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.PART_QUESTIONS);
const vehiclePartsComponent = await getLazyLoadedComponent(fmgPageValues.VEHICLE_PARTS);
const moldingQuestionsComponent = await getLazyLoadedComponent(fmgPageValues.MOLDING_QUESTIONS);
const capabilityQuestionsComponent = await getLazyLoadedComponent(
fmgPageValues.CAPABILITY_QUESTIONS
);
const quoteComponent = await getLazyLoadedComponent(fmgPageValues.QUOTE);
const serviceLocationComponent = await getLazyLoadedComponent(fmgPageValues.SERVICE_LOCATION);
const scheduleComponent = await getLazyLoadedComponent(fmgPageValues.SCHEDULE);
const skipVin = await skipVinLookup();
if (!vehicleDamageComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.VEHICLE;
} else if (!estimateComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.VEHICLE_DAMAGE;
} else {
if (quoteComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.QUOTE;
} else if (capabilityQuestionsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.CAPABILITY_QUESTIONS;
} else if (moldingQuestionsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.MOLDING_QUESTIONS;
} else if (vehiclePartsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.VEHICLE_PARTS;
} else if (partQuestionsComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.PART_QUESTIONS;
} else if (
// capture vin
vinLookupComponent.methods.arePagePrerequisitesValid() &&
!skipVin
) {
return fmgPageValues.VIN_LOOKUP;
} else {
// do not capture vin
return fmgPageValues.ESTIMATE;
}
}
}
/*
Overrides functionality to go to the YMMS pages in certain cases.
If this is not one of the cases, it returns the 'to' fmgPage value.
*/
/* istanbul ignore next */
function overrideYmmsDirectionIfNeeded(toRoute) {
const fmgPageValue = toRoute.query[queryStrings.FMG_PAGE];
if (store.getters.payment.insuranceCoverage.isVerified) {
switch (fmgPageValue) {
case fmgPageValues.VEHICLE: {
return fmgPageValues.VEHICLE_DAMAGE;
}
default: {
return fmgPageValue;
}
}
} else {
return fmgPageValue;
}
}
/*
Determine if the page is a vin related page.
*/
/* istanbul ignore next */
function isVinRelatedPage(toRoute) {
const fmgPageValue = toRoute.query[queryStrings.FMG_PAGE];
return (
fmgPageValue === fmgPageValues.VIN_LOOKUP ||
fmgPageValue === fmgPageValues.LICENSE_PLATE_LOOKUP ||
fmgPageValue === fmgPageValues.ADDRESS_LOOKUP ||
fmgPageValue === fmgPageValues.ADDRESS_VEHICLES ||
fmgPageValue === fmgPageValues.ESTIMATE
);
}
async function getLazyLoadedComponent(pageName) { async function getLazyLoadedComponent(pageName) {
return (await lazyLoadComponent(pageName)()).default; return (await lazyLoadComponent(pageName)()).default;
} }

View file

@ -1,7 +1,4 @@
import { import * as navigationHelper from "@/helpers/heritage-integration/navigation-helper";
getPageToRouteExistingOrderTo,
navigateToHeritageFunnel,
} from "@/helpers/heritage-integration/navigation-helper";
import * as orderHelper from "@/helpers/heritage-integration/order-helper"; import * as orderHelper from "@/helpers/heritage-integration/order-helper";
import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js"; import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
@ -14,12 +11,54 @@ import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
import store from "@/store"; import store from "@/store";
import router from "@/router"; import router from "@/router";
const getPageToRouteExistingOrderTo = navigationHelper.getPageToRouteExistingOrderTo;
const navigateToHeritageFunnel = navigationHelper.navigateToHeritageFunnel;
// Mock Lazy Load // Mock Lazy Load
jest.mock("@/router/dynamic-routing/component-loader.js", () => ({ jest.mock("@/router/dynamic-routing/component-loader.js", () => ({
lazyLoadComponent: jest.fn(), lazyLoadComponent: jest.fn(),
})); }));
describe("getPageToRouteExistingOrderTo", () => { describe("getPageToRouteExistingOrderTo", () => {
describe("Explicit vs. Implicit Routing", () => {
test("Should call explicit routing if `fmgPage` parameter is present in query", async () => {
// Arrange
const toRoute = {
query: {
fmgPage: "schedule",
},
};
mockLazyLoadComponentReturnValues();
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
// If direct, should be "schedule".
// Otherwise, not.
expect(result).toBe("schedule");
});
test("Should call implicit routing if `fmgPage` parameter is NOT present in query", async () => {
// Arrange
const toRoute = {
query: {},
};
mockLazyLoadComponentReturnValues();
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
// If direct, should be "schedule".
// Otherwise, not.
expect(result).not.toBe("schedule");
});
});
describe("Implicit Routing", () => {
test("should return vehicle", async () => { test("should return vehicle", async () => {
// Arrange // Arrange
const toRoute = { const toRoute = {
@ -242,6 +281,190 @@ describe("getPageToRouteExistingOrderTo", () => {
//Assert //Assert
expect(result).toBe(fmgPageValues.PART_QUESTIONS); expect(result).toBe(fmgPageValues.PART_QUESTIONS);
}); });
test("should return quote, if not verified insurance", async () => {
// Arrange
const toRoute = {
query: {},
};
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
store.commit(storeMutations.UPDATE_MAKE, "acura");
// Mock out the lazy load calls for all components.
mockLazyLoadComponentReturnValues({
[fmgPageValues.VEHICLE]: true,
[fmgPageValues.VEHICLE_DAMAGE]: true,
[fmgPageValues.ESTIMATE]: true,
[fmgPageValues.CAPABILITY_QUESTIONS]: false,
[fmgPageValues.MOLDING_QUESTIONS]: false,
[fmgPageValues.VEHICLE_PARTS]: false,
[fmgPageValues.PART_QUESTIONS]: true,
[fmgPageValues.VIN_LOOKUP]: false,
[fmgPageValues.QUOTE]: true,
});
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
//Assert
expect(result).toBe(fmgPageValues.QUOTE);
});
test("should not return pages beyond quote even if prerequisites are met", async () => {
// Arrange
const toRoute = {
query: {},
};
store.commit(storeMutations.UPDATE_IS_REPAIR, false);
store.commit(storeMutations.UPDATE_MAKE, "acura");
// Mock out the lazy load calls for all components.
mockLazyLoadComponentReturnValues({
[fmgPageValues.VEHICLE]: true,
[fmgPageValues.VEHICLE_DAMAGE]: true,
[fmgPageValues.ESTIMATE]: true,
[fmgPageValues.CAPABILITY_QUESTIONS]: false,
[fmgPageValues.MOLDING_QUESTIONS]: false,
[fmgPageValues.VEHICLE_PARTS]: false,
[fmgPageValues.PART_QUESTIONS]: true,
[fmgPageValues.VIN_LOOKUP]: false,
[fmgPageValues.QUOTE]: true,
[fmgPageValues.SERVICE_LOCATION]: true,
[fmgPageValues.SCHEDULE]: true,
});
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
//Assert
expect(result).toBe(fmgPageValues.QUOTE);
});
});
describe("Explicit Routing", () => {
test("Returns the value passed in in nominal case", async () => {
// Arrange
const toRoute = {
query: {
fmgPage: "testValue",
},
};
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
expect(result).toBe("testValue");
});
describe("Verified users", () => {
test("Replace navigation to `vehicle` with `vehicle-damage`", async () => {
// Arrange
const toRoute = {
query: {
fmgPage: fmgPageValues.VEHICLE,
},
};
store.commit(storeMutations.UPDATE_IS_VERIFIED_INSURANCE, true);
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
expect(result).toBe(fmgPageValues.VEHICLE_DAMAGE);
});
test("Replace navigation to `quote` with `heritage`", async () => {
// Arrange
const toRoute = {
query: {
fmgPage: fmgPageValues.QUOTE,
},
};
store.commit(storeMutations.UPDATE_IS_VERIFIED_INSURANCE, true);
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
expect(result).toBe(fmgPageValues.HERITAGE);
});
test("Replace navigation to `insurance-company` with `heritage`", async () => {
// Arrange
const toRoute = {
query: {
fmgPage: fmgPageValues.INSURANCE_COMPANY,
},
};
store.commit(storeMutations.UPDATE_IS_VERIFIED_INSURANCE, true);
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
expect(result).toBe(fmgPageValues.HERITAGE);
});
});
describe("Non-verified users", () => {
test("Don't replace navigation to `vehicle` with `vehicle-damage`", async () => {
// Arrange
const toRoute = {
query: {
fmgPage: fmgPageValues.VEHICLE,
},
};
store.commit(storeMutations.UPDATE_IS_VERIFIED_INSURANCE, false);
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
expect(result).toBe(fmgPageValues.VEHICLE);
});
test("Don't replace navigation to `quote` with `heritage`", async () => {
// Arrange
const toRoute = {
query: {
fmgPage: fmgPageValues.QUOTE,
},
};
store.commit(storeMutations.UPDATE_IS_VERIFIED_INSURANCE, false);
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
expect(result).toBe(fmgPageValues.QUOTE);
});
test("Don't replace navigation to `insurance-company` with `heritage`", async () => {
// Arrange
const toRoute = {
query: {
fmgPage: fmgPageValues.INSURANCE_COMPANY,
},
};
store.commit(storeMutations.UPDATE_IS_VERIFIED_INSURANCE, false);
// Act
const result = await getPageToRouteExistingOrderTo(toRoute);
// Assert
expect(result).toBe(fmgPageValues.INSURANCE_COMPANY);
});
});
});
}); });
describe("navigateToHeritageFunnel", () => { describe("navigateToHeritageFunnel", () => {

View file

@ -105,6 +105,12 @@ const routes = [
const pageToRedirectTo = await getPageToRouteExistingOrderTo(to); const pageToRedirectTo = await getPageToRouteExistingOrderTo(to);
// This logic may determine that the user should be sent to heritage -- if so, do that here.
if (pageToRedirectTo === fmgPageValues.HERITAGE) {
await navigateToHeritageFunnel({ shouldSaveSession: false });
return next(false);
}
// Assign our fmgPage so it will load normally like the other pages. // Assign our fmgPage so it will load normally like the other pages.
to.query.fmgPage = pageToRedirectTo; to.query.fmgPage = pageToRedirectTo;
} }