Merge pull request #1354 from Safelite/bug/chloeherd/analytics-mismatch

Bug/chloeherd/analytics mismatch
This commit is contained in:
chloeherdsafelite 2023-09-22 10:29:05 -04:00 committed by GitHub
commit e024258980
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 703 additions and 224 deletions

View file

@ -12,8 +12,8 @@ export default {
method,
endpoint,
payload,
logApiCall = true,
isFormData = false,
logApiCall = false,
pageNameToLog = null,
additionalSuccessEventDataHandler,
}) {
return new Promise((resolve, reject) => {
@ -37,13 +37,11 @@ export default {
if (additionalSuccessEventDataHandler) {
additionalEventData = "_" + additionalSuccessEventDataHandler(response);
}
const pageName = analyticsMixIn.methods.getPageName();
const nextPageName = router.lastNavigationPage || pageName;
const endpointWithoutParams =
analyticsMixIn.methods.removeParamsFromEndpoint(endpoint);
analyticsMixIn.methods.pushEventToGA(
GaCategories.API_RESPONSE,
`${nextPageName}_${endpointWithoutParams}`,
`${pageNameToLog}_${endpointWithoutParams}`,
`${GaLabels.SUCCESS}${additionalEventData}`,
true
);

View file

@ -54,10 +54,11 @@ export function includesWindshieldReplacement() {
return windshieldMatches.length > 0;
}
export async function isGlassAvailableForCarId(carId) {
const newGlassOptions = await baseMixin.methods.dispatchStoreAction(
export async function isGlassAvailableForCarId(carId, pageNameToLog) {
const newGlassOptions = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_DAMAGE_OPTIONS,
{ carId: carId }
{ carId: carId },
pageNameToLog
);
const currentGlassOptions = store.getters.damage.glassToReplace;

View file

@ -11,6 +11,13 @@ jest.mock("@/mixins/base-mixin.js", () => ({
},
};
}),
dispatchStoreActionWithLogging: jest.fn().mockImplementation(() => {
return {
data: {
windshieldOptions: { availableReplacementOptions: ["windshield"] },
},
};
}),
},
}));
@ -77,7 +84,7 @@ describe("damage-helper.js", () => {
];
// Act
const isGlassAvailable = await isGlassAvailableForCarId();
const isGlassAvailable = await isGlassAvailableForCarId("id", "testName");
// Assert
expect(isGlassAvailable).toEqual(true);
@ -91,7 +98,7 @@ describe("damage-helper.js", () => {
{ glassLocation: "Windshield", glassName: "sideWindow" },
];
const isGlassAvailable = await isGlassAvailableForCarId();
const isGlassAvailable = await isGlassAvailableForCarId("id", "testName");
// Assert
expect(isGlassAvailable).toEqual(false);

View file

@ -45,10 +45,10 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}) {
Used to navigate to the heritage funnel with the correct query string and url.
*/
export async function navigateToHeritageFunnel({ shouldSaveSession, loadingModal }) {
export async function navigateToHeritageFunnel({ shouldSaveSession, pageNameToLog, loadingModal }) {
// Create the order (or save existing order) when navigating to Heritage Funnel.
if (shouldSaveSession) {
await saveSession({ shouldAwaitSaveSessionQueue: true });
await saveSession({ pageNameToLog: pageNameToLog, shouldAwaitSaveSessionQueue: true });
}
if (loadingModal && loadingModal.showModal) {

View file

@ -14,7 +14,7 @@ import { storeMutations } from "@/constants/store-mutations";
it will reset the state and go back to the start of the funnel.
*/
export async function loadSessionIfPresent(isConceptInsurance) {
export async function loadSessionIfPresent(isConceptInsurance, pageNameToLog) {
const funnelCookie = getFunnelCookie();
// Do nothing if there is no cookie or session to use for loading.
@ -42,7 +42,8 @@ export async function loadSessionIfPresent(isConceptInsurance) {
funnelCookie.ReferralDate,
funnelCookie.ReferralParentAccountNumber,
funnelCookie.ReferralCorrelationId,
isConceptInsurance
isConceptInsurance,
pageNameToLog
)
)?.data;
}
@ -52,17 +53,17 @@ export async function loadSessionIfPresent(isConceptInsurance) {
This will also set Referral information in the store after saving, and then
update the cookie. To force synchronous behavior pass in 'true' for shouldAwaitSaveSessionQueue
*/
export async function saveSession({ shouldAwaitSaveSessionQueue = false }) {
export async function saveSession({ pageNameToLog, shouldAwaitSaveSessionQueue = false }) {
var saveSessionPromise;
if (store.getters.applicationUser.saveSessionPromise) {
// queue newest request after current saveSessionPromise resolves
saveSessionPromise = store.getters.applicationUser.saveSessionPromise.then(() => {
// get a new saveSessionPromise
return saveSessionHelper();
return saveSessionHelper(pageNameToLog);
});
} else {
// create an initial saveSessionPromise
saveSessionPromise = saveSessionHelper();
saveSessionPromise = saveSessionHelper(pageNameToLog);
}
store.commit(storeMutations.UPDATE_SAVE_SESSION_PROMISE, saveSessionPromise);
// await here to allow for a caller to await and make the function synchronous
@ -83,12 +84,13 @@ async function loadSession(
referralDate,
parentAccountNumber,
referralCorrelationId,
isConceptInsurance
isConceptInsurance,
pageNameToLog
) {
// await the saveSessionPromise in the store to make sure we're loading up to date information
await store.getters.applicationUser.saveSessionPromise;
const response = await baseMixin.methods.dispatchStoreAction(
const response = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.LOAD_SESSION,
{
savedSessionId: savedSessionId?.toString(),
@ -98,6 +100,7 @@ async function loadSession(
parentAccountNumber,
isConceptInsurance,
},
pageNameToLog,
false
);
@ -107,8 +110,12 @@ async function loadSession(
/*
Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing
*/
async function saveSessionHelper() {
const savedSessionInfo = await baseMixin.methods.dispatchStoreAction(storeActions.SAVE_SESSION);
async function saveSessionHelper(pageNameToLog) {
const savedSessionInfo = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.SAVE_SESSION,
null,
pageNameToLog
);
// Update the store with information received from the saveSession response
await baseMixin.methods.dispatchStoreAction(
storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE,

View file

@ -170,11 +170,13 @@ describe("saveSession", () => {
const mocks = setupMocksForJsFiles(mockData);
// Act
await saveSession({});
await saveSession({ pageNameToLog: "test" });
// Assert
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
storeActions.SAVE_SESSION
expect(mocks.baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledWith(
storeActions.SAVE_SESSION,
null,
"test"
);
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
storeActions.UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE,
@ -231,7 +233,7 @@ describe("saveSession", () => {
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
// Act
await saveSession({});
await saveSession({ pageNameToLog: "test" });
// Assert
expect(cookieHelper.getFunnelCookie().DidHeritageFunnelUpdateLast).toEqual(false);

View file

@ -44,6 +44,16 @@ export function getMountOptions(mockData) {
});
}
});
mocks.dispatchStoreActionWithLogging = jest.fn();
mocks.dispatchStoreActionWithLogging.mockImplementation((actionName) => {
let actionFilterResult = mockData.actionList?.filter((x) => x.actionName == actionName);
if (actionFilterResult?.length === 1) {
return Promise.resolve({
data: actionFilterResult[0].data,
});
}
});
// Mock const files
mocks.storeActions = storeActions;
@ -141,5 +151,16 @@ function setupBaseMixinDispatchStoreAction(mockData) {
});
}
});
baseMixin.methods.dispatchStoreActionWithLogging = jest.fn();
baseMixin.methods.dispatchStoreActionWithLogging.mockImplementation((actionName) => {
let actionFilterResult = mockData.actionList.filter((x) => x.actionName == actionName);
if (actionFilterResult.length > 0 && actionFilterResult.length === 1) {
return Promise.resolve({
data: actionFilterResult[0].data,
});
}
});
}
}

View file

@ -471,7 +471,7 @@ describe("address-lookup.vue", () => {
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith(
expect(wrapper.vm.dispatchStoreActionWithLogging).toHaveBeenCalledWith(
"lookupVinByAddress",
{
licenseLastName: undefined,
@ -479,12 +479,17 @@ describe("address-lookup.vue", () => {
licenseStreetAddress: "1234 Main St",
licenseZip: "43215",
},
"address-lookup",
false
);
expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith("validateZip", {
zip: "43215",
});
expect(wrapper.vm.dispatchStoreActionWithLogging).toHaveBeenCalledWith(
"validateZip",
{
zip: "43215",
},
"address-lookup"
);
});
});

View file

@ -224,7 +224,7 @@ export default {
// Vehicle info change in the flow, use a variable to keep track and commit to state at the end.
let vehicleInfoToCommit = {};
const vinLookupResponse = this.dispatchStoreAction(
const vinLookupResponse = this.dispatchStoreActionWithLogging(
storeActions.LOOKUP_VIN_BY_ADDRESS,
{
licenseLastName: this.customerQuestions.lastName,
@ -232,6 +232,7 @@ export default {
licenseZip: this.customerQuestions.addressQuestions.zipCode,
licenseState: this.customerQuestions.addressQuestions.state,
},
"address-lookup",
false
);
@ -244,12 +245,20 @@ export default {
{
resultKey: "serviceZipValidationResponse",
promise: this.serviceZipCode
? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
zip: this.serviceZipCode,
})
: this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
zip: this.customerQuestions.addressQuestions.zipCode,
}),
? this.dispatchStoreActionWithLogging(
storeActions.VALIDATE_ZIP,
{
zip: this.serviceZipCode,
},
"address-lookup"
)
: this.dispatchStoreActionWithLogging(
storeActions.VALIDATE_ZIP,
{
zip: this.customerQuestions.addressQuestions.zipCode,
},
"address-lookup"
),
},
];
@ -284,7 +293,8 @@ export default {
this.displayMatchedDifferentVehicleAlert = true;
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
carFound.carId
carFound.carId,
"address-lookup"
);
// Update button "Continue with..."

View file

@ -175,9 +175,13 @@ export default {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {
const vinLookup = await this.dispatchStoreAction(storeActions.LOOKUP_VEHICLE_BY_VIN, {
vin: this.selectedVehicle.vin,
}).catch(() => {
const vinLookup = await this.dispatchStoreActionWithLogging(
storeActions.LOOKUP_VEHICLE_BY_VIN,
{
vin: this.selectedVehicle.vin,
},
"address-vehicles"
).catch(() => {
this.$refs.navbar.removeLoader();
});
@ -186,7 +190,8 @@ export default {
}
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
vinLookup.data.carId
vinLookup.data.carId,
"address-vehicles"
);
await this.dispatchStoreAction(

View file

@ -237,6 +237,11 @@ describe("capabilityQuestions.vue", () => {
data: [],
};
});
wrapper.vm.dispatchStoreActionWithLogging = jest.fn(() => {
return {
data: [],
};
});
// Act
wrapper.vm.forwardButtonAction();
@ -272,6 +277,11 @@ describe("capabilityQuestions.vue", () => {
data: [],
};
});
wrapper.vm.dispatchStoreActionWithLogging = jest.fn(() => {
return {
data: [],
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
// Act
@ -325,7 +335,12 @@ describe("capabilityQuestions.vue", () => {
data: [],
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
wrapper.vm.dispatchStoreActionWithLogging = jest.fn(() => {
return {
data: [],
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreActionWithLogging");
// Act
wrapper.vm.forwardButtonAction();
@ -334,9 +349,10 @@ describe("capabilityQuestions.vue", () => {
//Assert
expect(spy).toHaveBeenNthCalledWith(
2,
1,
"getPartFromCapabilityQuestionAnswer",
"Windshield",
"capability-questions",
false
);
@ -368,6 +384,11 @@ describe("capabilityQuestions.vue", () => {
data: [],
};
});
wrapper.vm.dispatchStoreActionWithLogging = jest.fn(() => {
return {
data: [],
};
});
wrapper.vm.navigateForward = jest.fn();
// Act

View file

@ -162,9 +162,10 @@ export default {
const partsOrQuestions = this.partsOrQuestionsData;
for (let answer of questionAnswersArray) {
const partFromCapabilityQuestionAnswer = (
await this.dispatchStoreAction(
await this.dispatchStoreActionWithLogging(
this.storeActions.GET_PART_FROM_CAPABILITY_QUESTION_ANSWER,
answer.glassLocation,
"capability-questions",
false
)
).data;

View file

@ -162,9 +162,10 @@ export default {
var vinByAddressPromise;
if (zip) {
vinByAddressPromise = baseMixin.methods.dispatchStoreAction(
vinByAddressPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.IS_VIN_BY_ADDRESS_PERMISSIBLE,
zip,
{ zip: zip },
"estimate",
false
);
}
@ -259,13 +260,16 @@ export default {
if (vehicleChangedDuringPolicyLookupInHeritage) {
navigateToHeritageFunnel({
shouldSaveSession: true,
pageNameToLog: "estimate",
loadingModal: this.$refs.loadingModal,
});
} else if (this.$store.getters.order.referralNumber?.length === 6) {
await this.navigateForwardWithSingleCarMatch();
} else if (this.isRepair) {
const supportingItemsPromise = await this.dispatchStoreAction(
storeActions.GET_SUPPORTING_ITEMS
const supportingItemsPromise = await this.dispatchStoreActionWithLogging(
storeActions.GET_SUPPORTING_ITEMS,
null,
"estimate"
);
const promiseResultMap = [
@ -284,7 +288,7 @@ export default {
);
// call saveSession here - navigateWithSaving saves too late in the flow
await saveSession({});
await saveSession({ pageNameToLog: "estimate" });
return this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_NO_QUESTIONS,
this.$route

View file

@ -120,7 +120,7 @@ describe("license-plate-lookup.vue", () => {
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
wrapper.vm.navigateForward = jest.fn();
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
wrapper.vm.dispatchStoreActionWithLogging = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
vehicle: {
@ -157,7 +157,7 @@ describe("license-plate-lookup.vue", () => {
});
// Mock store action call
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
wrapper.vm.dispatchStoreActionWithLogging = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
vehicle: {
@ -201,7 +201,7 @@ describe("license-plate-lookup.vue", () => {
wrapper.vm.navigateForward = jest.fn();
// Mock store action call
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
wrapper.vm.dispatchStoreActionWithLogging = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
vehicle: {
@ -242,7 +242,7 @@ describe("license-plate-lookup.vue", () => {
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {
return "";
});
wrapper.vm.dispatchStoreAction = jest.fn();
wrapper.vm.dispatchStoreActionWithLogging = jest.fn();
await wrapper.vm.navigateForward();
@ -379,7 +379,7 @@ describe("license-plate-lookup.vue", () => {
return { data: { vehicle: { carId: "C00000" } } };
});
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
wrapper.vm.dispatchStoreActionWithLogging = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
vehicle: {
@ -417,7 +417,7 @@ describe("license-plate-lookup.vue", () => {
await wrapper.setData({ registrationZip: "00000" });
navigateToHeritage.navigateToHeritageFunnel = jest.fn();
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
wrapper.vm.dispatchStoreActionWithLogging = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
vehicle: {
@ -449,7 +449,7 @@ describe("license-plate-lookup.vue", () => {
await wrapper.setData({ registrationZipCode: "00000" });
navigateToHeritage.navigateToHeritageFunnel = jest.fn();
wrapper.vm.dispatchStoreAction = jest.fn().mockImplementation(() =>
wrapper.vm.dispatchStoreActionWithLogging = jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
vehicle: {

View file

@ -200,9 +200,10 @@ export default {
async forwardButtonAction() {
this.resetWarningsAndErrors();
const registrationZipValidationResponse = this.dispatchStoreAction(
const registrationZipValidationResponse = this.dispatchStoreActionWithLogging(
storeActions.VALIDATE_ZIP,
{ zip: this.registrationZipCode }
{ zip: this.registrationZipCode },
"license-plate-lookup"
);
// Settle promises and get results
@ -215,9 +216,13 @@ export default {
// If serviceZipCode is not set, then sets the response to the registrationZipValidationResponse. Calls VALIDATE_ZIP if the serviceZipCode is set.
resultKey: "serviceZipValidationResponse",
promise: this.serviceZipCode
? this.dispatchStoreAction(storeActions.VALIDATE_ZIP, {
zip: this.serviceZipCode,
})
? this.dispatchStoreActionWithLogging(
storeActions.VALIDATE_ZIP,
{
zip: this.serviceZipCode,
},
"license-plate-lookup"
)
: registrationZipValidationResponse,
},
];
@ -261,7 +266,8 @@ export default {
this.displayMatchedDifferentVehicleAlert = true;
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
vinLookup.data.vehicle.carId
vinLookup.data.vehicle.carId,
"license-plate-lookup"
);
// Update button "Continue with..."
@ -313,9 +319,10 @@ export default {
return await this.navigateForward();
},
lookupVin(plate, state) {
return this.dispatchStoreAction(
return this.dispatchStoreActionWithLogging(
storeActions.LOOKUP_VIN_BY_PLATE,
{ licensePlate: plate, licenseState: state },
"license-plate-lookup",
false
);
},

View file

@ -248,6 +248,13 @@ describe("partQuestions.vue...", () => {
},
};
});
wrapper.vm.dispatchStoreActionWithLogging = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
// Act
wrapper.vm.forwardButtonAction();
@ -281,6 +288,13 @@ describe("partQuestions.vue...", () => {
},
};
});
wrapper.vm.dispatchStoreActionWithLogging = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
// Act
@ -328,7 +342,14 @@ describe("partQuestions.vue...", () => {
},
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
wrapper.vm.dispatchStoreActionWithLogging = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreActionWithLogging");
// Act
wrapper.vm.forwardButtonAction();
@ -336,7 +357,7 @@ describe("partQuestions.vue...", () => {
await nextTick();
//Assert
expect(spy).toHaveBeenNthCalledWith(2, "getParts");
expect(spy).toHaveBeenNthCalledWith(1, "getParts", null, "part-questions");
wrapper.unmount();
});
@ -362,6 +383,13 @@ describe("partQuestions.vue...", () => {
},
};
});
wrapper.vm.dispatchStoreActionWithLogging = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
wrapper.vm.navigateForward = jest.fn();
// Act

View file

@ -145,7 +145,11 @@ export default {
);
// call API parts method
const partsLookup = await this.dispatchStoreAction(this.storeActions.GET_PARTS);
const partsLookup = await this.dispatchStoreActionWithLogging(
this.storeActions.GET_PARTS,
null,
"part-questions"
);
const glassPartsForStore = partsLookup.data.glassPieceParts;

View file

@ -36,6 +36,10 @@ jest.mock("@/mixins/base-mixin", () => ({
if (action === mockPriceOrderStoreAction) return items;
else return mockStoreActionResults[action];
},
dispatchStoreActionWithLogging(action, items, pageName, encode) {
if (action === mockPriceOrderStoreAction) return items;
else return mockStoreActionResults[action];
},
getTierOnePackagePrice() {
return mockTierOnePrice;
},

View file

@ -86,12 +86,20 @@ export default {
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
const wipersPromise = baseMixin.methods.dispatchStoreAction(storeActions.GET_WIPERS);
const rainDefensePromise = baseMixin.methods.dispatchStoreAction(
storeActions.GET_RAIN_DEFENSE
const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_WIPERS,
null,
"quote"
);
const supportingItemsPromise = baseMixin.methods.dispatchStoreAction(
storeActions.GET_SUPPORTING_ITEMS
const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_RAIN_DEFENSE,
null,
"quote"
);
const supportingItemsPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_SUPPORTING_ITEMS,
null,
"quote"
);
const promiseResultMap = [
@ -124,11 +132,12 @@ export default {
...clonedGlassParts,
];
const pricingResults = await baseMixin.methods.dispatchStoreAction(
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
availableLineItems: availableLineItems,
},
"quote",
false
);
@ -236,6 +245,7 @@ export default {
if (payment.isInsurance) {
navigateToHeritageFunnel({
shouldSaveSession: true,
pageNameToLog: "quote",
loadingModal: this.$refs.loadingModal,
});
} else {

View file

@ -31,9 +31,15 @@ export default {
},
methods: {
loadInitialData() {
const wipersPromise = baseMixin.methods.dispatchStoreAction(storeActions.GET_WIPERS);
const rainDefensePromise = baseMixin.methods.dispatchStoreAction(
storeActions.GET_RAIN_DEFENSE
const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_WIPERS,
null,
"review"
);
const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_RAIN_DEFENSE,
null,
"review"
);
const promiseResultMap = [

View file

@ -2,11 +2,12 @@ import { storeActions } from "@/constants/store-actions";
import baseMixin from "@/mixins/base-mixin.js";
export async function getAlertReasons(ctu) {
const alertReasons = await baseMixin.methods.dispatchStoreAction(
const alertReasons = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_ALERT_REASONS_BY_CTU,
{
ctu: ctu,
}
},
"schedule"
);
return Promise.resolve(alertReasons);

View file

@ -70,6 +70,65 @@ jest.mock("@/mixins/base-mixin.js", () => ({
]);
}
}),
dispatchStoreActionWithLogging: jest.fn().mockImplementation((storeAction) => {
if (storeAction === "getShopTimeSlots") {
return {
data: {
estimatedServiceMinutesMinimum: 90,
estimatedServiceMinutesMaximum: 120,
days: [
{
date: "2023-12-01",
timeSlots: [
{
id: "06747-01820-S-B*20424*7 AM",
startTime: "07:00",
endTime: "08:00",
offerPremium: false,
},
],
},
],
},
};
}
if (storeAction === "getMobilePremiumFee") {
return Promise.resolve({
data: {
partNumber: "EARLY BIRD",
description: null,
partType: "EARLY BIRD",
laborAmount: 0,
sellingPrice: 14.99,
kitPrice: 0,
},
});
}
if (storeAction === "priceOrderItemsAndSaveServerData") {
return Promise.resolve([
{
partNumber: "EARLY BIRD",
description: null,
partType: "EARLY BIRD",
laborAmount: 0,
sellingPrice: 14.99,
kitPrice: 0,
},
]);
}
if (storeAction === "saveSupportingItemsSuppressingStateResetting") {
return Promise.resolve([
{
partNumber: "EARLY BIRD",
description: null,
partType: "EARLY BIRD",
laborAmount: 0,
sellingPrice: 14.99,
kitPrice: 0,
},
]);
}
}),
},
}));
@ -226,10 +285,11 @@ describe("schedule.vue...", () => {
);
// Assert
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledTimes(3);
expect(baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
expect(baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledTimes(3);
expect(baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledWith(
"getShopTimeSlots",
expect.anything(),
expect.anything(),
expect.anything()
);
});

View file

@ -168,9 +168,10 @@ const getAvailableDates = async (
const makeParallelCalls = async () => {
await Promise.all(
storeActionConfigs.map(async (storeAction) => {
const timeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
const timeSlotsResponse = await baseMixin.methods.dispatchStoreActionWithLogging(
storeAction.storeAction,
storeAction.payload,
"schedule",
false
);
timeSlotsResponsesData.estimatedServiceMinutesMinimum =
@ -218,17 +219,20 @@ export default {
preSelectedDate: preSelectedDate,
});
const premiumFeePromise = baseMixin.methods.dispatchStoreAction(
storeActions.GET_MOBILE_PREMIUM_FEE
const premiumFeePromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_MOBILE_PREMIUM_FEE,
null,
"schedule"
);
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
if (result.data) {
return baseMixin.methods.dispatchStoreAction(
return baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
availableLineItems: [result.data],
},
"schedule",
false
);
} else {

View file

@ -2,42 +2,45 @@ import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin.js";
export async function getPricedMobileFeePart(serviceZipCode) {
export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) {
if (!serviceZipCode) {
return Promise.resolve(null);
}
const zipCodeData = await baseMixin.methods.getZipCodeData(serviceZipCode);
const zipCodeData = await baseMixin.methods.getZipCodeData(serviceZipCode, pageNameToLog);
// Get the Mobile Fee Part
const mobileFeePart = await baseMixin.methods.dispatchStoreAction(
const mobileFeePart = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_MOBILE_FEE_PART,
null,
pageNameToLog,
false
);
// Get the Mobile Fee Part Price
const pricingResults = await baseMixin.methods.dispatchStoreAction(
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
availableLineItems: [mobileFeePart.data],
serviceZipCode: serviceZipCode,
serviceZipCodeCtu: zipCodeData.zipCodeCtu,
},
pageNameToLog,
false
);
return Promise.resolve(pricingResults[0]);
}
export async function getServiceabilityDetails(serviceZipCode, lineItems) {
export async function getServiceabilityDetails(serviceZipCode, lineItems, pageNameToLog) {
// Get the Mobile Fee Part
const serviceabilityDetails = await baseMixin.methods.dispatchStoreAction(
const serviceabilityDetails = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_SERVICEABILITY_DETAILS,
{
serviceZipCode: serviceZipCode,
lineItems: lineItems,
},
pageNameToLog,
false
);
@ -51,7 +54,7 @@ export async function getAvailabilityRating(
providerNumber
) {
// For a given shop provider number and date range, get the appointment time slots available
const shopTimeSlots = await baseMixin.methods.dispatchStoreAction(
const shopTimeSlots = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_SHOP_TIME_SLOTS,
{
providerNumber: providerNumber,
@ -59,6 +62,7 @@ export async function getAvailabilityRating(
endDate: endDate,
shopAppointmentType: shopAppointmentType,
},
"service-location",
false
);

View file

@ -188,6 +188,47 @@ jest.mock("@/mixins/base-mixin.js", () => ({
});
}
if (actionName === mockStoreActionGetShopTimeSlots) {
if (request.providerNumber == "0000001") {
return Promise.resolve(mockGetShopTimeSlotsGoodAvailability);
}
return Promise.resolve(mockGetShopTimeSlotsLowAvailability);
}
}),
dispatchStoreActionWithLogging: jest.fn().mockImplementation((actionName, request) => {
if (actionName === mockStoreActionGetMobileFeePart) {
return Promise.resolve({
data: {
partNumber: "MOBILE FEE",
description: "MOBILE FEE",
partType: "FEE",
},
});
}
if (actionName === mockStoreActionPriceOrderItemsAndSaveServerData) {
return Promise.resolve([
{
partNumber: "MOBILE FEE",
description: "MOBILE FEE",
partType: "FEE",
laborAmount: 49.99,
sellingPrice: 0,
kitPrice: 0,
},
]);
}
if (actionName === mockStoreActionGetServiceabilityDetails) {
return Promise.resolve({
isGlassServiceableInshop: true,
isRecalibrationServiceableInshop: true,
isGlassServiceableMobile: true,
isRecalibrationServiceableMobile: true,
});
}
if (actionName === mockStoreActionGetShopTimeSlots) {
if (request.providerNumber == "0000001") {
return Promise.resolve(mockGetShopTimeSlotsGoodAvailability);

View file

@ -229,7 +229,8 @@ export default {
) {
// Validate the Zip Code
const zipCodeData = await this.getZipCodeData(
this.internalModel.addressQuestions.zipCode
this.internalModel.addressQuestions.zipCode,
"service-location"
);
if (!zipCodeData.isValid) {
@ -238,10 +239,17 @@ export default {
} else {
// retrieve mobile fee part
const serviceZipCode = this.internalModel.addressQuestions.zipCode;
const mobileFeePart = await getPricedMobileFeePart(serviceZipCode);
const mobileFeePart = await getPricedMobileFeePart(
serviceZipCode,
"service-location"
);
// retrieve serviceability details
const serviceabilityDetails = await getServiceabilityDetails(serviceZipCode);
const serviceabilityDetails = await getServiceabilityDetails(
serviceZipCode,
null,
"service-location"
);
// update content related to service zip code
this.$emit("updated-mobile-fee-part", mobileFeePart);

View file

@ -177,11 +177,15 @@ export default {
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
const serviceZipCode = store.getters.order.serviceLocation.zipCode;
const getZipCodeData = baseMixin.methods.getZipCodeData(serviceZipCode);
const getZipCodeData = baseMixin.methods.getZipCodeData(serviceZipCode, "service-location");
const serviceabilityDetailsPromise = getServiceabilityDetails(serviceZipCode);
const serviceabilityDetailsPromise = getServiceabilityDetails(
serviceZipCode,
null,
"service-location"
);
const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode);
const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode, "service-location");
const shopQuestionInitialDataPromise = shopQuestion.methods.loadInitialData(serviceZipCode);

View file

@ -133,7 +133,10 @@ export default {
if (this.internalModel.zipCode !== this.modelValue.zipCode) {
this.resetAlerts();
const zipCodeData = await this.getZipCodeData(this.internalModel.zipCode);
const zipCodeData = await this.getZipCodeData(
this.internalModel.zipCode,
"service-location"
);
if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true;
@ -144,10 +147,17 @@ export default {
// retrieve mobile fee part
const serviceZipCode = this.internalModel.zipCode;
const mobileFeePart = await getPricedMobileFeePart(serviceZipCode);
const mobileFeePart = await getPricedMobileFeePart(
serviceZipCode,
"service-location"
);
// retrieve serviceability details
const serviceabilityDetails = await getServiceabilityDetails(serviceZipCode);
const serviceabilityDetails = await getServiceabilityDetails(
serviceZipCode,
null,
"service-location"
);
// update content related to service zip code
this.$emit("updated-mobile-fee-part", mobileFeePart);

View file

@ -126,9 +126,13 @@ export default {
return this.loadData(serviceZipCode);
},
loadData(serviceZipCode) {
return baseMixin.methods.dispatchStoreAction(storeActions.GET_PROVIDERS, {
serviceZipCode: serviceZipCode,
});
return baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_PROVIDERS,
{
serviceZipCode: serviceZipCode,
},
"service-location"
);
},
initializeComponent(shopQuestionInitialData) {
this.shopProviders = shopQuestionInitialData.shopProviders;

View file

@ -173,9 +173,10 @@ describe("vehicle-damage.vue", () => {
//Assert
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace);
expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith(
expect(baseMixin.methods.dispatchStoreActionWithLogging).toBeCalledWith(
storeActions.GET_DAMAGE_OPTIONS,
{ carId: "C00000000" }
{ carId: "C00000000" },
"vehicle-damage"
);
});
@ -268,9 +269,10 @@ describe("vehicle-damage.vue", () => {
//Assert
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
expect(wrapper.vm.selectedGlassToReplace()).toEqual(expectedGlassToReplace);
expect(baseMixin.methods.dispatchStoreAction).toBeCalledWith(
expect(baseMixin.methods.dispatchStoreActionWithLogging).toBeCalledWith(
storeActions.GET_DAMAGE_OPTIONS,
{ carId: "C00000000" }
{ carId: "C00000000" },
"vehicle-damage"
);
});
});
@ -789,6 +791,7 @@ function setupMocks({ pageHeaderWidgetHeaderText, mountOptionsMockData, funnelCo
mountOptionsMockData = Object.assign(mountOptionsMockDataDefault, mountOptionsMockData);
//Mock api responses
baseMixin.methods.dispatchStoreAction = jest.fn();
baseMixin.methods.dispatchStoreActionWithLogging = jest.fn();
const apiResponses = {
cmsContent: {
FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,

View file

@ -110,9 +110,10 @@ export default {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
const damageOptionsPromise = baseMixin.methods.dispatchStoreAction(
const damageOptionsPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_DAMAGE_OPTIONS,
{ carId: store.getters.vehicle.carId }
{ carId: store.getters.vehicle.carId },
"vehicle-damage"
);
// Settle promises and get results
@ -345,8 +346,10 @@ export default {
);
if (this.isWindshieldRepair) {
const supportingItems = await this.dispatchStoreAction(
storeActions.GET_SUPPORTING_ITEMS
const supportingItems = await this.dispatchStoreActionWithLogging(
storeActions.GET_SUPPORTING_ITEMS,
null,
"vehicle-damage"
);
this.dispatchStoreAction(
this.storeActions.SAVE_SUPPORTING_ITEMS,

View file

@ -122,9 +122,10 @@ export default {
const experimentForLogging = store.getters.applicationUser.experiments.find(
(e) => e.universeName === experimentUniverses.CONCEPT_FUNNEL
);
const yearQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction(
const yearQuestionInitialDataPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_VEHICLE_YEARS,
{}
{},
"vehicle"
);
var makeQuestionInitialDataPromise = null;
var modelQuestionInitialDataPromise = null;
@ -135,35 +136,38 @@ export default {
store.getters.order.vehicle.model &&
store.getters.order.vehicle.style
) {
makeQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction(
makeQuestionInitialDataPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_VEHICLE_MAKES,
{
year: store.getters.order.vehicle.year,
}
},
"vehicle"
);
modelQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction(
modelQuestionInitialDataPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_VEHICLE_MODELS,
{
year: store.getters.order.vehicle.year,
make: store.getters.order.vehicle.make,
}
},
"vehicle"
);
styleQuestionInitialDataPromise = baseMixin.methods.dispatchStoreAction(
styleQuestionInitialDataPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_VEHICLE_STYLES,
{
year: store.getters.order.vehicle.year,
make: store.getters.order.vehicle.make,
model: store.getters.order.vehicle.model,
}
},
"vehicle"
);
}
// If the concept funnel experiment is found, as it should be when coming from safelite.com, then log the experiment exposure.
if (experimentForLogging !== undefined) {
// Log experiment exposure
baseMixin.methods.dispatchStoreAction(
baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.LOG_EXPERIMENT_EXPOSURE,
{
userId: getDeviceIdValue(),
@ -171,6 +175,7 @@ export default {
pageName: to.query.fmgPage,
experiment: experimentForLogging,
},
"vehicle",
false
);
}
@ -299,12 +304,16 @@ export default {
},
methods: {
getVehicle(year, make, model, style) {
return this.dispatchStoreAction(this.storeActions.GET_VEHICLE, {
year: year,
make: make,
model: model,
style: style,
});
return this.dispatchStoreActionWithLogging(
this.storeActions.GET_VEHICLE,
{
year: year,
make: make,
model: model,
style: style,
},
"vehicle"
);
},
arePagePrerequisitesValid() {
return true;
@ -349,24 +358,36 @@ export default {
return store.getters.vehicle.style;
},
async getMakeOptions(year) {
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MAKES, {
year: year,
});
return await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_VEHICLE_MAKES,
{
year: year,
},
"vehicle"
);
},
async getModelOptions(year, make) {
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_MODELS, {
year: year,
make: make,
});
return await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_VEHICLE_MODELS,
{
year: year,
make: make,
},
"vehicle"
);
},
async getStyleOptions(year, make, model) {
return await baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_STYLES, {
year: year,
make: make,
model: model,
});
return await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_VEHICLE_STYLES,
{
year: year,
make: make,
model: model,
},
"vehicle"
);
},
getImagefromStore() {
return store.getters.vehicle.imageUrl;

View file

@ -249,9 +249,10 @@ export default {
// If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation
if (!this.vinPopulatedOnPageLoad) {
const vehicleLookupResponse = this.dispatchStoreAction(
const vehicleLookupResponse = this.dispatchStoreActionWithLogging(
storeActions.LOOKUP_VEHICLE_BY_VIN,
{ vin: this.vin }
{ vin: this.vin },
"vin-lookup"
);
// Settle promises and get results
@ -305,7 +306,8 @@ export default {
this.displayMatchedDifferentVehicleAlert = true;
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
resultMap.vehicleLookupResponse.carId
resultMap.vehicleLookupResponse.carId,
"vin-lookup"
);
// Update button "Continue with..."
@ -393,7 +395,11 @@ export default {
},
getVinFromImage(image) {
return new Promise((resolve, reject) => {
this.dispatchStoreAction(storeActions.LOOKUP_VIN_BY_IMAGE, image)
this.dispatchStoreActionWithLogging(
storeActions.LOOKUP_VIN_BY_IMAGE,
image,
"vin-lookup"
)
.then((response) => {
if (response.data.length > 0) {
resolve(response.data[0]);

View file

@ -31,6 +31,19 @@ export default {
return store.dispatch(type, payload);
},
dispatchStoreActionWithLogging(type, payload, pageNameToLog, encodePayload = true) {
// Encode the payload if required
if (encodePayload) {
encodeUriData(payload);
}
const wrappedParams = {
payload: payload,
pageNameToLog: pageNameToLog,
};
return store.dispatch(type, wrappedParams);
},
savePageDataToStore(page, data) {
store.commit(storeMutations.UPDATE_PAGE_DATA, { page: page, data: data });
},
@ -50,10 +63,16 @@ export default {
const footerInfoBox = document.querySelector(".footer#infoBox");
return footerInfoBox ? footerInfoBox.offsetHeight : 0;
},
async getZipCodeData(zipCode) {
const serviceZipValidationResponse = await this.dispatchStoreAction(
async getZipCodeData(zipCode, pageNameToLog = null) {
const pageName = pageNameToLog ?? this.$options?.name;
if (pageName == null) {
console.log("Missed a spot.");
}
const serviceZipValidationResponse = await this.dispatchStoreActionWithLogging(
storeActions.VALIDATE_ZIP,
{ zip: zipCode }
{ zip: zipCode },
pageName
);
return {

View file

@ -101,8 +101,8 @@ describe("baseMixin.js", () => {
test("getZipCodeData calls dispatch", () => {
const mixIn = getMixInInstance({});
mixIn.methods.dispatchStoreAction = jest.fn();
mixIn.methods.dispatchStoreAction.mockReturnValue({
mixIn.methods.dispatchStoreActionWithLogging = jest.fn();
mixIn.methods.dispatchStoreActionWithLogging.mockReturnValue({
data: { isValid: true, isServiceable: true, state: "OH" },
});
const type = "";
@ -118,7 +118,7 @@ describe("baseMixin.js", () => {
mixIn.methods.getZipCodeData(type, payload);
expect(mixIn.methods.dispatchStoreAction).toBeCalled();
expect(mixIn.methods.dispatchStoreActionWithLogging).toBeCalled();
});
});

View file

@ -408,12 +408,13 @@ export default {
for (let partOrQuestion of partsOrQuestions) {
if (this.hasCapabilityQuestions([partOrQuestion])) {
let capabilityQuestionsForGlassLocation = (
await baseMixin.methods.dispatchStoreAction(
await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_CAPABILITY_QUESTIONS,
{
carId: store.getters.vehicle.carId,
partNumber: partOrQuestion.parts[0].partNumber,
}
},
currentPage
)
).data;
@ -449,11 +450,13 @@ export default {
if (store.getters.order.referralNumber?.length === 6) {
navigateToHeritageFunnel({
shouldSaveSession: true,
pageNameToLog: currentPage,
loadingModal: self.$refs.loadingModal,
});
} else if (payment.isInsurance && payment.insuranceCoverage.isVerified) {
navigateToHeritageFunnel({
shouldSaveSession: true,
pageNameToLog: currentPage,
loadingModal: self.$refs.loadingModal,
});
} else {

View file

@ -6,12 +6,16 @@ import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
export default {
methods: {
async navigateForwardWithSingleCarMatch() {
const pageName = this.$options?.name;
// If we have not already saved a session, we need to save one now before the lengthy call to getPartsOrQuestions
if (!store.getters.applicationUser.savedSessionId) {
await saveSession({});
await saveSession({ pageNameToLog: pageName });
}
const result = await this.dispatchStoreAction(storeActions.GET_PARTS_OR_QUESTIONS);
const result = await this.dispatchStoreAction(storeActions.GET_PARTS_OR_QUESTIONS, {
pageNameToLog: pageName,
});
const partsOrQuestions = result.data.partsOrQuestions;
vehicleQuestionsMixin.methods.navigateForward(partsOrQuestions, this);

View file

@ -72,7 +72,8 @@ const routes = [
? to.query.isInsurance == "true"
? true
: false
: null
: null,
to.query.fmgPage
);
const pageToRedirectTo = await getPageToRouteExistingOrderTo(to);
@ -172,7 +173,7 @@ router.afterEach(async (to, from) => {
store.getters.applicationUser.savedSessionId ||
store.getters.order.customer?.emailAddress
) {
await saveSession({});
await saveSession({ pageNameToLog: to.query.fmgPage });
}
}
@ -384,18 +385,26 @@ function arePagePrerequisitesValid(component) {
// Run SiteEntry and PageEntry triggers for experiments
async function runExperiments(nextPage) {
if (!store.getters.applicationUser.triggeredSiteEntry) {
await baseMixin.methods.dispatchStoreAction(storeActions.RUN_EXPERIMENTS_FOR_TRIGGER, {
userId: getDeviceIdValue(),
triggerEvent: experimentTriggers.SITE_ENTRY,
triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE,
});
await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.RUN_EXPERIMENTS_FOR_TRIGGER,
{
userId: getDeviceIdValue(),
triggerEvent: experimentTriggers.SITE_ENTRY,
triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE,
},
nextPage
);
}
await baseMixin.methods.dispatchStoreAction(storeActions.RUN_EXPERIMENTS_FOR_TRIGGER, {
userId: getDeviceIdValue(),
triggerEvent: experimentTriggers.PAGE_ENTRY,
triggerValue: nextPage,
});
await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.RUN_EXPERIMENTS_FOR_TRIGGER,
{
userId: getDeviceIdValue(),
triggerEvent: experimentTriggers.PAGE_ENTRY,
triggerValue: nextPage,
},
nextPage
);
}
export default router;

View file

@ -658,33 +658,39 @@ function getTimeSlotsAdditionalEventData(
// Export Actions
export const actions = {
// Vehicle API Actions
getVehicleYears(context) {
getVehicleYears(context, { pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleYears.method,
endpoint: endpoints.GetVehicleYears.url,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVehicleByYmms(context, { year, make, model, style }) {
lookupVehicleByYmms(context, { payload: { year, make, model, style }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVehicleByYmms.method,
endpoint: `${endpoints.LookupVehicleByYmms.url}/${year}/${make}/${model}/${style}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVehicleByVin(context, { vin }) {
lookupVehicleByVin(context, { payload: { vin }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVehicleByVin.method,
endpoint: endpoints.LookupVehicleByVin.url,
payload: {
vin: vin, // EX "1J4GW58S4XC541166"
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVinByPlate(context, { licensePlate, licenseState }) {
lookupVinByPlate(context, { payload: { licensePlate, licenseState }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVinByPlate.method,
endpoint: endpoints.LookupVinByPlate.url,
@ -692,12 +698,17 @@ export const actions = {
licensePlate: licensePlate,
licenseState: licenseState,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVinByAddress(
context,
{ licenseLastName, licenseStreetAddress, licenseZip, licenseState }
{
payload: { licenseLastName, licenseStreetAddress, licenseZip, licenseState },
pageNameToLog,
}
) {
return globalMethods.callHttpClient({
method: endpoints.LookupVinByAddress.method,
@ -708,10 +719,14 @@ export const actions = {
licenseZip: licenseZip,
licenseState: licenseState,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
lookupVinByImage(context, image) {
lookupVinByImage(context, { payload, pageNameToLog }) {
const image = payload;
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = (e) => {
@ -733,68 +748,84 @@ export const actions = {
method: endpoints.LookupVinByImage.method,
endpoint: endpoints.LookupVinByImage.url,
payload: data,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
});
},
isVinByAddressPermissible(context, zip) {
isVinByAddressPermissible(context, { payload: { zip }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.IsVinByAddressPermissible.method,
endpoint: `${endpoints.IsVinByAddressPermissible.url}?zipcode=${zip}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getVehicleMakes(context, { year }) {
getVehicleMakes(context, { payload: { year }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleMakes.method,
endpoint: `${endpoints.GetVehicleMakes.url}/${year}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getVehicleModels(context, { year, make }) {
getVehicleModels(context, { payload: { year, make }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleModels.method,
endpoint: `${endpoints.GetVehicleModels.url}/${year}/${make}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getVehicleStyles(context, { year, make, model }) {
getVehicleStyles(context, { payload: { year, make, model }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleStyles.method,
endpoint: `${endpoints.GetVehicleStyles.url}/${year}/${make}/${model}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getVehicle(context, { year, make, model, style }) {
getVehicle(context, { payload: { year, make, model, style }, pageNameToLog }) {
return globalMethods
.callHttpClient({
methods: endpoints.GetVehicle.method,
endpoint: `${endpoints.GetVehicle.url}/${year}/${make}/${model}/${style}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.then((response) => {
return response;
});
},
getDamageOptions(context, { carId }) {
getDamageOptions(context, { payload: { carId }, pageNameToLog }) {
return globalMethods.callHttpClient({
methods: endpoints.GetDamageOptions.method,
endpoint: `${endpoints.GetDamageOptions.url}/${carId}`,
payload: {},
additionalSuccessEventDataHandler: (response) =>
"QueryStringZip: " + getQuerystringParameter(queryStrings.ZIP_CODE),
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
validateZip(context, { zip }) {
validateZip(context, { payload: { zip }, pageNameToLog }) {
return globalMethods.callHttpClient({
methods: endpoints.ValidateZip.method,
endpoint: `${endpoints.ValidateZip.url}/${zip}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
@ -843,6 +874,8 @@ export const actions = {
payload: {
pageName: pageName,
},
logApiCall: true,
pageNameToLog: pageName,
});
},
@ -861,11 +894,16 @@ export const actions = {
pageName
),
payload: {},
logApiCall: true,
pageNameToLog: pageName,
});
},
// Analytics Actions
logExperimentExposure(context, { userId, sessionKey, pageName, experiment }) {
logExperimentExposure(
context,
{ payload: { userId, sessionKey, pageName, experiment }, pageNameToLog }
) {
return globalMethods.callHttpClient({
method: endpoints.LogExperimentExposureIfAssigned.method,
endpoint: endpoints.LogExperimentExposureIfAssigned.url,
@ -886,15 +924,19 @@ export const actions = {
pageName: pageName,
},
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
// Location API Actions
getAlertReasonsByCtu(context, { ctu }) {
getAlertReasonsByCtu(context, { payload: { ctu }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetAlertReasons.method,
endpoint: `${endpoints.GetAlertReasons.url}/${ctu}`,
payload: {},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
@ -1062,7 +1104,10 @@ export const actions = {
});
},
async runExperimentsForTrigger(context, { userId, triggerEvent, triggerValue }) {
async runExperimentsForTrigger(
context,
{ payload: { userId, triggerEvent, triggerValue }, pageNameToLog }
) {
if (triggerEvent == experimentTriggers.SITE_ENTRY) {
context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true);
}
@ -1079,6 +1124,8 @@ export const actions = {
method: endpoints.RunExperimentsForTrigger.method,
endpoint: endpoints.RunExperimentsForTrigger.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
context.commit(storeMutations.UPDATE_EXPERIMENTS, response.data.experiments);
@ -1093,7 +1140,7 @@ export const actions = {
},
// PartsOrQuestions API Actions
async getPartsOrQuestions(context) {
async getPartsOrQuestions(context, { pageNameToLog }) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
@ -1115,6 +1162,8 @@ export const actions = {
zip: zipCode,
vin: vin,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
// Flatten location and name properties
@ -1126,7 +1175,7 @@ export const actions = {
},
// Parts API Actions
async getParts(context) {
async getParts(context, { pageNameToLog }) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
@ -1151,6 +1200,8 @@ export const actions = {
zip: zipCode,
vin: vin,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
// Flatten location and name properties
@ -1161,13 +1212,15 @@ export const actions = {
return response;
},
getWipers(context) {
getWipers(context, { pageNameToLog }) {
const carId = context.getters.vehicle.carId;
const serviceZipCode = context.getters.order.serviceLocation.zipCode;
return globalMethods
.callHttpClient({
method: endpoints.GetWipers.method,
endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.catch((error) => {
// The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
@ -1175,14 +1228,16 @@ export const actions = {
});
},
getRainDefense(context) {
getRainDefense(context, { pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetRainDefense.method,
endpoint: endpoints.GetRainDefense.url,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getMobileFeePart(context) {
getMobileFeePart(context, { pageNameToLog }) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
const parentAccountNumber = context.getters.payment.parentAccountNumber;
const billToAccountNumber = 87291; // TODO: MAKE THIS REAL
@ -1190,10 +1245,12 @@ export const actions = {
return globalMethods.callHttpClient({
method: endpoints.GetMobileFeePart.method,
endpoint: `${endpoints.GetMobileFeePart.url}/${damageType}/${parentAccountNumber}/${billToAccountNumber}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getServiceabilityDetails(context, { serviceZipCode }) {
getServiceabilityDetails(context, { payload: { serviceZipCode }, pageNameToLog }) {
const lineItemsWithOnlyPartNumbers = context.getters.order.lineItems.supportingItems.map(
(lineItem) => ({
partNumber: lineItem.partNumber,
@ -1217,20 +1274,24 @@ export const actions = {
return globalMethods.callHttpClient({
method: endpoints.GetServiceabilityDetails.method,
endpoint: `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&${lineItems}&${glassPieces}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getProviders(context, { serviceZipCode }) {
getProviders(context, { payload: { serviceZipCode }, pageNameToLog }) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
const shopRadiusInMiles = 100;
return globalMethods.callHttpClient({
method: endpoints.GetProviders.method,
endpoint: `${endpoints.GetProviders.url}/${serviceZipCode}/${damageType}/${shopRadiusInMiles}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getSupportingItems(context) {
getSupportingItems(context, { pageNameToLog }) {
const glassPartsArray = context.getters.lineItems.glassParts ?? [];
const carId = context.getters.vehicle.carId;
const isRepair = context.getters.damage.isRepair;
@ -1246,17 +1307,22 @@ export const actions = {
parts: glassPartsArray,
numberOfRepairChips: isRepair ? numberOfChips : 0,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getCapabilityQuestions(context, { carId, partNumber }) {
getCapabilityQuestions(context, { payload: { carId, partNumber }, pageNameToLog }) {
return globalMethods.callHttpClient({
method: endpoints.GetCapabilityQuestions.method,
endpoint: `${endpoints.GetCapabilityQuestions.url}/${carId}/${partNumber}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getPartFromCapabilityQuestionAnswer(context, glassLocation) {
getPartFromCapabilityQuestionAnswer(context, { payload, pageNameToLog }) {
const glassLocation = payload;
const pageData = context.getters.pageData(fmgPageValues.CAPABILITY_QUESTIONS);
const part = pageData.partsOrQuestions.find((x) => x.glassLocation === glassLocation)
@ -1273,10 +1339,15 @@ export const actions = {
part,
capabilityAnswerResults: capabilityQuestionAnswersForPart,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
getShopTimeSlots(context, { startDate, endDate, shopAppointmentType, providerNumber }) {
getShopTimeSlots(
context,
{ payload: { startDate, endDate, shopAppointmentType, providerNumber }, pageNameToLog }
) {
const order = context.state.order;
const vehicle = context.state.order.vehicle;
@ -1331,6 +1402,8 @@ export const actions = {
method: endpoints.GetShopTimeSlots.method,
endpoint: endpoints.GetShopTimeSlots.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
additionalSuccessEventDataHandler: (response) =>
getTimeSlotsAdditionalEventData(
response.data.provisionalTriggers,
@ -1341,7 +1414,7 @@ export const actions = {
});
},
getMobileTimeSlots(context, { startDate, endDate }) {
getMobileTimeSlots(context, { payload: { startDate, endDate }, pageNameToLog }) {
const order = context.state.order;
const vehicle = context.state.order.vehicle;
let lineItems = [
@ -1393,6 +1466,8 @@ export const actions = {
method: endpoints.GetMobileTimeSlots.method,
endpoint: endpoints.GetMobileTimeSlots.url,
payload: payload,
logApiCall: true,
pageNameToLog: pageNameToLog,
additionalSuccessEventDataHandler: (response) =>
getTimeSlotsAdditionalEventData(
response.data.provisionalTriggers,
@ -1402,18 +1477,20 @@ export const actions = {
});
},
getMobilePremiumFee(context) {
getMobilePremiumFee(context, { pageNameToLog }) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
const paymentType = context.getters.order.payment.isInsurance ? "Insurance" : "Cash";
return globalMethods.callHttpClient({
method: endpoints.GetMobilePremiumFee.method,
endpoint: `${endpoints.GetMobilePremiumFee.url}/${paymentType}/${damageType}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
},
// Session API Actions
saveSession(context) {
saveSession(context, { pageNameToLog }) {
const vehicle = context.getters.vehicle;
const damage = context.getters.damage;
const order = context.state.order;
@ -1519,6 +1596,8 @@ export const actions = {
eon: order.eon,
},
},
logApiCall: true,
pageNameToLog: pageNameToLog,
additionalSuccessEventDataHandler: (response) =>
"Email provided: " + (order.customer.emailAddress ? "true" : "false"),
});
@ -1527,12 +1606,15 @@ export const actions = {
loadSession(
context,
{
savedSessionId,
referralNumber,
referralDate,
parentAccountNumber,
referralCorrelationId,
isConceptInsurance,
payload: {
savedSessionId,
referralNumber,
referralDate,
parentAccountNumber,
referralCorrelationId,
isConceptInsurance,
},
pageNameToLog,
}
) {
const order = context.state.order;
@ -1548,6 +1630,8 @@ export const actions = {
parentAccountNumber: parentAccountNumber,
referralCorrelationId: referralCorrelationId,
},
logApiCall: true,
pageNameToLog: pageNameToLog,
})
.then(
async (response) => {
@ -1905,7 +1989,7 @@ export const actions = {
// Price order actions
async priceOrderItemsAndSaveServerData(
context,
{ availableLineItems, serviceZipCode, serviceZipCodeCtu }
{ payload: { availableLineItems, serviceZipCode, serviceZipCodeCtu }, pageNameToLog }
) {
const zipCodeToUse = serviceZipCode
? serviceZipCode
@ -1945,6 +2029,8 @@ export const actions = {
const response = await globalMethods.callHttpClient({
method: endpoints.PriceOrderItems.method,
endpoint: `${endpoints.PriceOrderItems.url}?${queryString}`,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
context.commit(storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA, response.data.serverData);

View file

@ -370,7 +370,7 @@ describe("Actions", () => {
});
// Assert
const response = await actions.getVehicleYears(context);
const response = await actions.getVehicleYears(context, { pageNameToLog: "test" });
expect(response.data).toEqual([2023, 2022, 2021]);
});
@ -385,13 +385,15 @@ describe("Actions", () => {
});
// Assert
const response = await actions.lookupVehicleByYmms(
context,
"2019",
"Acura",
"ILX",
"4 DOOR SEDAN"
);
const response = await actions.lookupVehicleByYmms(context, {
payload: {
year: "2019",
make: "Acura",
model: "ILX",
style: "4 DOOR SEDAN",
},
pageNameToLog: "test",
});
expect(response.data).toEqual({ carId: "C00000001" });
});
@ -406,7 +408,12 @@ describe("Actions", () => {
});
// Assert
const response = await actions.lookupVehicleByVin(context, "12345678901234567");
const response = await actions.lookupVehicleByVin(context, {
payload: {
vin: "12345678901234567",
},
pageNameToLog: "test",
});
expect(response.data).toEqual({ carId: "C0000001" });
});
@ -421,7 +428,10 @@ describe("Actions", () => {
});
// Assert
const response = await actions.lookupVinByPlate(context, "12345678901234567");
const response = await actions.lookupVinByPlate(context, {
payload: { licensePlate: "12345678901234567", licenseState: "OH" },
pageNameToLog: "test",
});
expect(response.data).toEqual({ carId: "C00000001" });
});
@ -438,7 +448,10 @@ describe("Actions", () => {
});
// Act
const response = await actions.lookupVinByImage(context, image);
const response = await actions.lookupVinByImage(context, {
payload: image,
pageNameToLog: "test",
});
// Assert
expect(response.data).toEqual(["1C6JJTAG3NL134044"]);
@ -458,7 +471,9 @@ describe("Actions", () => {
// Act
// Assert
await expect(actions.lookupVinByImage(context, image)).rejects.toEqual("An error occurred");
await expect(
actions.lookupVinByImage(context, { payload: image, pageNameToLog: "test" })
).rejects.toEqual("An error occurred");
});
it("getVehicleMakes action, should return makes list", async () => {
@ -471,7 +486,10 @@ describe("Actions", () => {
});
// Assert
const response = await actions.getVehicleMakes(context, "2019");
const response = await actions.getVehicleMakes(context, {
payload: { year: "2019" },
pageNameToLog: "test",
});
expect(response.data).toEqual(["Acura", "Honda"]);
});
@ -486,7 +504,10 @@ describe("Actions", () => {
});
// Assert
const response = await actions.getVehicleModels(context, "2019", "Acura");
const response = await actions.getVehicleModels(context, {
payload: { year: "2019", make: "Acura" },
pageNameToLog: "test",
});
expect(response.data).toEqual(["ILX", "RDX"]);
});
@ -501,7 +522,10 @@ describe("Actions", () => {
});
// Assert
const response = await actions.getVehicleStyles(context, "2019", "Acura", "ILX");
const response = await actions.getVehicleStyles(context, {
payload: { year: "2019", make: "Acura", model: "ILX" },
pageNameToLog: "test",
});
expect(response.data).toEqual({ style: "4 DOOR SEDAN" });
});
@ -516,7 +540,10 @@ describe("Actions", () => {
});
// Assert
const response = await actions.getVehicle(context, "C00000000");
const response = await actions.getVehicle(context, {
payload: { year: "2019", make: "Acura", model: "IDX", style: "4-door sedan" },
pageNameToLog: "test",
});
expect(response.data).toEqual({ carId: "C00000000", category: "CAR" });
});
@ -530,7 +557,10 @@ describe("Actions", () => {
return Promise.resolve({ data: ["Windshield", "DriversFrontDoor"] });
});
const response = await actions.getDamageOptions(context, "C00000000");
const response = await actions.getDamageOptions(context, {
payload: { carId: "C00000000" },
pageNameToLog: "test",
});
// Assert
expect(response.data).toEqual(["Windshield", "DriversFrontDoor"]);
@ -552,7 +582,10 @@ describe("Actions", () => {
});
});
const response = await actions.validateZip(context, "43212");
const response = await actions.validateZip(context, {
payload: { zip: "43212" },
pageNameToLog: "test",
});
// Assert
expect(response.data).toEqual({
@ -730,7 +763,7 @@ describe("Actions", () => {
});
// Act
const response = await actions.saveSession(context);
const response = await actions.saveSession(context, { pageNameToLog: "test" });
// Assert
expect(response.data).toEqual({ referralNumber: 123 });
@ -750,7 +783,10 @@ describe("Actions", () => {
// Act
const response = await actions.loadSession(context, {
savedSessionId: "",
payload: {
savedSessionId: "",
},
pageNameToLog: "test",
});
// Assert
@ -776,7 +812,10 @@ describe("Actions", () => {
// Act
const response = await actions.loadSession(context, {
savedSessionId: "",
payload: {
savedSessionId: "",
},
pageNameToLog: "test",
});
// Assert
@ -801,7 +840,10 @@ describe("Actions", () => {
// Act
const response = await actions.loadSession(context, {
savedSessionId: "",
payload: {
savedSessionId: "",
},
pageNameToLog: "test",
});
// Assert
@ -1718,7 +1760,10 @@ describe("Actions", () => {
// Act
await actions.runExperimentsForTrigger(context, {
triggerEvent: experimentTriggers.SITE_ENTRY,
payload: {
triggerEvent: experimentTriggers.SITE_ENTRY,
},
pageNameToLog: "test",
});
// Assert
@ -1752,7 +1797,10 @@ describe("Actions", () => {
// Act
await actions.runExperimentsForTrigger(context, {
triggerEvent: "NotSiteEntry",
payload: {
triggerEvent: "NotSiteEntry",
},
pageNameToLog: "test",
});
// Assert