diff --git a/jest.config.js b/jest.config.js
index 052e1c47b..ce4aa3ad6 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -27,7 +27,6 @@ module.exports = {
"!src/layouts/insurance/*.vue", // Temp test exclusion while in development
"!src/layouts/insurance-company/*.vue", // Temp test exclusion while in development
"!src/layouts/insurance-company/insurance-company-question/*.vue", // Temp test exclusion while in development
- "!src/layouts/return-user/*.vue", // Temp test exclusion while in development
// END
], // ! means exclude from coverage.
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js
index c972d8118..29d36d091 100644
--- a/src/constants/endpoints.js
+++ b/src/constants/endpoints.js
@@ -125,7 +125,7 @@ const endpoints = {
method: "POST",
},
SaveQuote: {
- url: "/order/api/v1/order/initiate-saved-progress-email",
+ url: "/order/api/v1/order/save-progress",
method: "POST",
},
GetSignature: {
@@ -168,6 +168,10 @@ const endpoints = {
url: "/analytics/api/v1/analytics/initialize",
method: "POST",
},
+ LogPartQuestions: {
+ url: "/analytics/api/v1/analytics/log-part-questions",
+ method: "POST",
+ },
GetExperimentsByUser: {
url: "/analytics/api/v1/analytics/get-experiments",
method: "GET",
diff --git a/src/constants/experiments.js b/src/constants/experiments.js
index 83555fc04..92d27a4a1 100644
--- a/src/constants/experiments.js
+++ b/src/constants/experiments.js
@@ -1,6 +1,7 @@
const experimentUniverses = {
CONCEPT_FUNNEL: "ConceptFunnel",
RECAL_PRICE_REMOVAL: "NextGen_RecalPriceRemoval",
+ MSR: "MSR",
};
const experimentSettings = {
@@ -16,6 +17,7 @@ const experimentSettings = {
RECAL_PRICE_REMOVE: "RecalPriceRemove",
INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL: "NextGen_InternalInsuranceTabDisplayThreshold",
INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL: "NextGen_ExternalInsuranceTabDisplayThreshold",
+ DISPLAY_MSR: "DisplayMSR",
};
const experimentTriggers = {
diff --git a/src/constants/header-keys.js b/src/constants/header-keys.js
index 2f7598244..d9b3578c4 100644
--- a/src/constants/header-keys.js
+++ b/src/constants/header-keys.js
@@ -5,4 +5,5 @@ export const headerKeys = {
SESSION_SEQUENCE_NUMBER: "X-Session-Sequence-Number",
TRANSACTION_ID: "X-Transaction-Id",
EON: "X-Enterprise-Order-Number",
+ LOG_ENABLED: "log-enabled"
};
diff --git a/src/constants/part-number-strings.js b/src/constants/part-number-strings.js
new file mode 100644
index 000000000..c32864a87
--- /dev/null
+++ b/src/constants/part-number-strings.js
@@ -0,0 +1,7 @@
+const partNumberStrings = {
+ // Recalibration
+ MOBILE_STATIC_RECAL_FEE: "RECAL MOBILE",
+ MOBILE_DUAL_RECAL_FEE: "RECAL MOBILEDUAL",
+};
+
+export { partNumberStrings };
diff --git a/src/constants/store-actions.js b/src/constants/store-actions.js
index 45a18bace..aee8d705f 100644
--- a/src/constants/store-actions.js
+++ b/src/constants/store-actions.js
@@ -42,10 +42,6 @@ const storeActions = {
VALIDATE_ZIP: "validateZip",
PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA: "priceOrderItemsAndSaveServerData",
TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA: "taxOrderItemsAndSaveServerData",
- LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure",
- LOG_PAGE_VIEW: "logPageView",
- LOG_CUSTOM_EVENT: "logCustomEvent",
- INITIALIZE_SESSION: "initializeSession",
GET_EXPERIMENTS_BY_USER: "GetExperimentsByUser",
RUN_EXPERIMENTS_FOR_TRIGGER: "runExperimentsForTrigger",
CLEAR_VIN: "clearVin",
@@ -57,6 +53,13 @@ const storeActions = {
GET_BILL_TO_ACCOUNT_NUMBER: "getBillToAccountNumber",
GET_RECAL_PARTS_AND_SAVE_TO_LINE_ITEMS: "getRecalPartsAndSaveToLineItems",
+ // Analytics
+ LOG_EXPERIMENT_EXPOSURE: "logExperimentExposure",
+ LOG_PAGE_VIEW: "logPageView",
+ LOG_CUSTOM_EVENT: "logCustomEvent",
+ INITIALIZE_SESSION: "initializeSession",
+ LOG_PART_QUESTIONS: "logPartQuestions",
+
// DEPENDENCY MUTATIONS
RESET_VEHICLE_STATE_AND_DEPENDENCIES: "resetVehicleStateAndDependencies",
RESET_DAMAGE_STATE_AND_DEPENDENCIES: "resetDamageAndDependencies",
diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue
index 58260e831..72ed56035 100644
--- a/src/digital-components/modal/modal.vue
+++ b/src/digital-components/modal/modal.vue
@@ -29,9 +29,10 @@
@@ -205,35 +207,63 @@ export default {
left: 0;
}
}
- .modal-footer {
- order: 3;
- padding: 0;
- }
- .modal-disclaimer {
- order: 4;
+ .modal.modal-component .modal-dialog .modal-content {
+ p.modal-body {
+ padding: 0;
+ }
+ .modal-body {
+ display: flex;
+ flex-direction: column;
+ padding: 0 1.5rem;
+
+ .textbox-question {
+ padding: 0;
+ margin: 0 0 1.5rem 0;
+
+ label {
+ text-align: left;
+ font-weight: 900;
+ }
+ }
+ }
+ .modal-body-inner {
+ text-align: center;
+ margin-bottom: 1.5rem;
+ }
+ .modal-footer {
+ padding: 0 1.5rem;
+ margin: 0 0 1.5rem 0;
+
+ button.btn {
+ order: 1;
+ margin-bottom: 1.5rem;
+ }
+ button.btn.skip-button {
+ padding: 0;
+ order: 2;
+ font-size: 1rem;
+ }
+ .modal-disclaimer {
+ font-size: 0.75rem;
+ text-align: left;
+ order: 3;
+ margin: 0;
+
+ a {
+ text-decoration: none;
+ }
+ }
+ }
}
&.progress-saved {
- .modal-footer,
- .save-progress-popup-question {
+ .modal-footer-button,
+ .modal-disclaimer {
display: none;
}
+ .skip-button {
+ margin-bottom: 0;
+ }
}
}
-.applied-promo {
- font-size: 0.875rem;
- font-weight: 500;
- line-height: 24px;
- color: $green;
-
- .promo-code {
- text-transform: uppercase;
- }
-}
-.alert {
- color: $red;
- font-size: 0.875rem;
- font-weight: 500;
- line-height: 24px;
-}
diff --git a/src/global-methods.js b/src/global-methods.js
index 77255e99d..ba6cec1ec 100644
--- a/src/global-methods.js
+++ b/src/global-methods.js
@@ -70,6 +70,7 @@ export default {
[headerKeys.REFERRAL_SEQUENCE_NUMBER]: order?.referralSequenceNumber,
[headerKeys.TRANSACTION_ID]: crypto.randomUUID(),
[headerKeys.EON]: order?.eon,
+ [headerKeys.LOG_ENABLED]: store.getters.applicationUser?.loggingOption ?? false,
};
axios({
diff --git a/src/helpers/boolean-helper.js b/src/helpers/boolean-helper.js
new file mode 100644
index 000000000..71016ef06
--- /dev/null
+++ b/src/helpers/boolean-helper.js
@@ -0,0 +1,19 @@
+export function getBoolFromString(str) {
+ // Catch edge cases
+ if (str === null || str === undefined) {
+ return false;
+ }
+
+ if (typeof str === "boolean") {
+ return str;
+ }
+
+ if (typeof str !== "string") {
+ return false;
+ }
+
+ // string logic
+ const toLower = str?.toLowerCase();
+
+ return toLower === "true";
+}
diff --git a/src/helpers/boolean-helper.spec.js b/src/helpers/boolean-helper.spec.js
new file mode 100644
index 000000000..189bd2a78
--- /dev/null
+++ b/src/helpers/boolean-helper.spec.js
@@ -0,0 +1,146 @@
+import { getBoolFromString } from "./boolean-helper";
+
+describe("getBoolFromString", () => {
+ describe("Happy paths", () => {
+ test('"true" -> true', () => {
+ const input = "true";
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(true);
+ });
+
+ test('"false" -> false', () => {
+ const input = "false";
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+
+ test('"other string" -> false', () => {
+ const input = "some random value";
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+ });
+
+ describe("Capitalization", () => {
+ test('"TRUE" -> true', () => {
+ const input = "TRUE";
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(true);
+ });
+
+ test('"True" -> true', () => {
+ const input = "True";
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(true);
+ });
+
+ test('"FALSE" -> false', () => {
+ const input = "FALSE";
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+
+ test('"False" -> false', () => {
+ const input = "False";
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+ });
+
+ describe("Graceful type errors", () => {
+ describe("Boolean", () => {
+ test("true -> true", () => {
+ const input = true;
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(true);
+ });
+
+ test("false -> false", () => {
+ const input = false;
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+ });
+
+ describe("Empty", () => {
+ test("undefined -> false", () => {
+ const input = undefined;
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+
+ test("null -> false", () => {
+ const input = null;
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+
+ test("{} -> false", () => {
+ const input = {};
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+ });
+
+ describe("Other types", () => {
+ test("1 -> false", () => {
+ const input = 1;
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+
+ test("Object -> false", () => {
+ const input = {
+ test: true,
+ true: true,
+ };
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+
+ test("function -> false", () => {
+ const input = () => true;
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+
+ test("array -> false", () => {
+ const input = [true];
+
+ const output = getBoolFromString(input);
+
+ expect(output).toBe(false);
+ });
+ });
+ });
+});
diff --git a/src/helpers/querystring-helper.js b/src/helpers/querystring-helper.js
index 38583b1ae..e6c488b1d 100644
--- a/src/helpers/querystring-helper.js
+++ b/src/helpers/querystring-helper.js
@@ -8,3 +8,17 @@ export function getQuerystringParameter(key) {
return lowerCaseParams.get(key) ? lowerCaseParams.get(key) : null;
}
+
+// if you add the fmgPage to the querystringobject before calling, then pass true for skipFmgPageName
+export function buildQuerystringObject(qso, skipFmgPageName = false) {
+ const queryString = window.location.search;
+ const urlParams = new URLSearchParams(queryString);
+
+ for (const [name, value] of urlParams) {
+ if (name.toLowerCase() === "fmgpage" && skipFmgPageName) {
+ continue;
+ }
+ qso[name] = value;
+ }
+ return qso;
+}
diff --git a/src/layouts/capability-questions/capability-questions.vue b/src/layouts/capability-questions/capability-questions.vue
index 57567e128..1896513a1 100644
--- a/src/layouts/capability-questions/capability-questions.vue
+++ b/src/layouts/capability-questions/capability-questions.vue
@@ -64,9 +64,7 @@ export default {
// Call the "next" function to complete the transition to this page.
next(async (vm) => {
vm.setCmsContent(resultMap.cmsContent);
- // turned off Save Your Progress for 1/23/25 release
- // to restore, uncomment line below
- // vm.showSaveProgressModal = !(emailFromStore?.length > 0);
+ vm.showSaveProgressModal = !(emailFromStore?.length > 0);
if (store.getters.externalParameterState?.isExternalParameter) {
if (store.getters.externalParameterServiceZip.zipCode) {
await baseMixin.methods.dispatchStoreAction(
diff --git a/src/layouts/confirmation/confirmation.vue b/src/layouts/confirmation/confirmation.vue
index d206a4bef..59a8b1a8b 100644
--- a/src/layouts/confirmation/confirmation.vue
+++ b/src/layouts/confirmation/confirmation.vue
@@ -120,6 +120,43 @@ export default {
async beforeRouteEnter(to, from, next) {
const hasRecalPriceRemoveExperiment = await store.getters.shouldHideRecalibration;
+ // send part question data to SPS API for logging
+ const orderFromStore = await deepClone(store.getters.order);
+ const ctu = orderFromStore.serviceLocation?.zipCodeCtu
+
+ const partsOrQuestions = orderFromStore.damage?.partQuestionAnswers;
+
+ partsOrQuestions.forEach(pqa => {
+ const payloadPartQuestions = [];
+ pqa.answeredQuestions.forEach(answer => {
+ payloadPartQuestions.push({
+ questionSeq: answer?.questionNum,
+ questionText: answer?.questionText,
+ answerText: answer?.selectedAnswerText,
+ basePart: pqa?.result,
+ });
+ });
+
+ const payload = {
+ eon: orderFromStore.eon,
+ ctu: ctu,
+ workOrderId: orderFromStore.workOrderId,
+ workOrderNumber: orderFromStore.workOrderNumber,
+ carId: orderFromStore.vehicle.carId,
+ glassLocation: pqa?.glassLocation,
+ partQuestions: payloadPartQuestions,
+ };
+
+ baseMixin.methods.dispatchStoreAction(
+ storeActions.LOG_PART_QUESTIONS,
+ payload,
+ false
+ );
+
+ });
+
+
+ // Create order
await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_ORDER); // This nulls the Store order
// Call APIs
diff --git a/src/layouts/molding-questions/molding-questions.vue b/src/layouts/molding-questions/molding-questions.vue
index 4da3588d7..1bcc3d7a8 100644
--- a/src/layouts/molding-questions/molding-questions.vue
+++ b/src/layouts/molding-questions/molding-questions.vue
@@ -64,9 +64,7 @@ export default {
// Call the "next" function to complete the transition to this page.
next(async (vm) => {
vm.setCmsContent(resultMap.cmsContent);
- // turned off Save Your Progress for 1/23/25 release
- // to restore, uncomment line below
- // vm.showSaveProgressModal = !(emailFromStore?.length > 0);
+ vm.showSaveProgressModal = !(emailFromStore?.length > 0);
if (store.getters.externalParameterState?.isExternalParameter) {
if (store.getters.externalParameterServiceZip.zipCode) {
await baseMixin.methods.dispatchStoreAction(
diff --git a/src/layouts/part-questions/part-questions.vue b/src/layouts/part-questions/part-questions.vue
index 37f005d48..f905e86c7 100644
--- a/src/layouts/part-questions/part-questions.vue
+++ b/src/layouts/part-questions/part-questions.vue
@@ -64,9 +64,7 @@ export default {
// Call the "next" function to complete the transition to this page.
next(async (vm) => {
vm.setCmsContent(resultMap.cmsContent);
- // turned off Save Your Progress for 1/23/25 release
- // to restore, uncomment line below
- // vm.showSaveProgressModal = !(emailFromStore?.length > 0);
+ vm.showSaveProgressModal = !(emailFromStore?.length > 0);
if (store.getters.externalParameterState?.isExternalParameter) {
if (store.getters.externalParameterServiceZip.zipCode) {
const serviceState = store.getters.order.serviceLocation.state;
diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue
index 5c6025b84..698c8bb09 100644
--- a/src/layouts/payment-method/payment-method.vue
+++ b/src/layouts/payment-method/payment-method.vue
@@ -156,6 +156,7 @@ import { mapTaxedLineItemsToStoreFormat } from "../../store";
import { coverageStatus } from "@/constants/insurance";
import { containsLineItemWithPartType } from "@/helpers/service-package-helper";
import { containsRecalParts } from "@/helpers/recal-helper";
+import { getBoolFromString } from "@/helpers/boolean-helper";
defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED));
defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED));
@@ -429,7 +430,7 @@ export default {
// prettier-ignore
{
const log = getQuerystringParameter(queryStrings.LOG);
- const logAsBool = (log?.toLowerCase() === "true");
+ const logAsBool = getBoolFromString(log);
if (logAsBool || !preReqResult) {
console.log("------------- payment-method.vue pagePrereqs start -----------------");
console.log(new Date() + " serviceLocationReqs::isMobile: " + isMobile);
@@ -786,7 +787,7 @@ export default {
shouldDisplayPiaAlert() {
return (
this.$route.query[queryStrings.DISPLAY_PIA_ALERT] ||
- eval(window.history.state.displayPiaAlert)
+ getBoolFromString(window.history.state.displayPiaAlert)
);
},
// Necessary to make the watcher of lineItems work
diff --git a/src/layouts/payment/payment.vue b/src/layouts/payment/payment.vue
index ce5e6bcbe..5ffb04faa 100644
--- a/src/layouts/payment/payment.vue
+++ b/src/layouts/payment/payment.vue
@@ -234,6 +234,7 @@ import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js"
import iframeResize from "../../../node_modules/iframe-resizer/js/iframeResizer.js";
import { routerParams } from "@/router/router-constants/router-params";
import { coverageStatus } from "@/constants/insurance";
+import { getBoolFromString } from "@/helpers/boolean-helper.js";
export default {
name: "payment",
@@ -800,7 +801,7 @@ export default {
shouldDisplayPiaAlert(payMethod) {
return (
this.$route.query[queryStrings.DISPLAY_PIA_ALERT] === payMethod ||
- eval(window.history.state.displayPiaAlert)
+ getBoolFromString(window.history.state.displayPiaAlert)
);
},
},
diff --git a/src/layouts/quote/quote.vue b/src/layouts/quote/quote.vue
index f3590cbc3..4428f6e40 100644
--- a/src/layouts/quote/quote.vue
+++ b/src/layouts/quote/quote.vue
@@ -159,6 +159,7 @@ import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigat
import { containsRecalParts } from "@/helpers/recal-helper";
import { externalParameterStatus } from "@/constants/external-parameters";
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
+import { getBoolFromString } from "@/helpers/boolean-helper";
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
@@ -293,12 +294,8 @@ export default {
// Call the "next" function to complete the transition to this page.
next(async (vm) => {
vm.setCmsContent(resultMap.cmsContent);
-
- // turned off Save Your Progress for 1/23/25 release
- // to restore, uncomment the 2 lines below
- // vm.showSaveProgressPopup = showSaveProgressPopup;
- // vm.showSaveProgressModal = showSaveProgressModal;
-
+ vm.showSaveProgressPopup = showSaveProgressPopup;
+ vm.showSaveProgressModal = showSaveProgressModal;
vm.addableVaps = addableVaps;
vm.lineItems = lineItems;
vm.availableLineItems = pricingResults;
@@ -407,7 +404,7 @@ export default {
baseMixin.methods.ResetExternalParamsAndHideModal();
} else {
// user came from an external source, however, the externalParms may have been reset on service-zip, property-questions, etc...
- if (eval(store.getters.externalParameterQuote?.isInsurance)) {
+ if (getBoolFromString(store.getters.externalParameterQuote?.isInsurance)) {
// did user intentionally select insurance?
vm.isInsuranceSelected = true;
vm.servicePackage = store.getters.externalParameterQuote.servicePackage;
diff --git a/src/layouts/return-user/return-user.spec.js b/src/layouts/return-user/return-user.spec.js
new file mode 100644
index 000000000..dc631ce62
--- /dev/null
+++ b/src/layouts/return-user/return-user.spec.js
@@ -0,0 +1,312 @@
+// Components
+import returnUser from "@/layouts/return-user/return-user.vue";
+
+// Supporting Files
+import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
+import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
+import { shallowMount } from "@vue/test-utils";
+import { getMountOptions } from "@/helpers/unit-test-helper";
+import baseMixin from "@/mixins/base-mixin.js";
+import { dispatchStoreAction } from "@/mixins/base-mixin.js";
+import store from "@/store";
+import router from "@/router";
+import navbar from "@/fmg-components/nav-bar/nav-bar";
+import { Form } from "vee-validate";
+import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
+import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
+import { settleAllPromises } from "@/helpers/layout-helper";
+import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
+import { deleteFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
+import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
+
+import { experimentSettings } from "../../constants/experiments";
+import { storeActions } from "@/constants/store-actions";
+import buttonMain from "@/ux-components/button-main/button-main";
+
+// Constants
+
+// Setup global mocks
+let mockStoreActionData = {};
+
+let mockStoreData = {};
+let mockExperimentSettings = {
+ experiments: [
+ {
+ universeName: "ConceptFunnel",
+ settings: {
+ SuppressVinCapture: false,
+ },
+ },
+ ],
+};
+
+function resetMockStoreData() {
+ mockStoreData = {
+ vehicle: {
+ year: "2000",
+ make: "TestMake",
+ model: "TestModel",
+ style: "TestStyle",
+ carId: "TestID",
+ vin: null,
+ registration: {
+ licensePlate: null,
+ },
+ },
+ serviceLocation: {
+ address: null,
+ address2: null,
+ city: null,
+ state: null,
+ zipCode: null,
+ zipCodeCtu: null,
+ appointmentType: null,
+ isVehicleProtected: null,
+ provider: {
+ providerNumber: null,
+ address: {
+ streetAddress: null,
+ city: null,
+ state: null,
+ zipCode: null,
+ zipCodeCtu: null,
+ },
+ },
+ techNotes: null,
+ },
+ customer: {
+ firstName: null,
+ lastName: null,
+ emailAddress: null,
+ phoneNumber: null,
+ isSmsOptIn: null,
+ },
+ damage: {
+ isRepair: false,
+ numberOfChips: null,
+ glassToReplace: [{ glassLocation: "Windshield", glassName: "windshield" }],
+ partQuestionAnswers: null,
+ moldingQuestionAnswers: null,
+ capabilityQuestionAnswers: null,
+ dateOfLoss: null,
+ damageCause: null,
+ },
+ lineItems: {
+ glassParts: [
+ {
+ canSafeliteRecalibrate: true,
+ childParts: [
+ {
+ kitPrice: 0,
+ laborAmount: 23.55,
+ partNumber: "GGG FW4896",
+ salesTax: 1.77,
+ sellingPrice: 0,
+ },
+ ],
+ color: "Green Tint",
+ description:
+ "solar, soundproofing, lane keep assist, lane departure warning system, w/adaptive cruise control",
+ id: "db22fd44-10dd-456f-979b-ff88cf68cca6",
+ kitPrice: 0,
+ laborAmount: 60,
+ partNumber: "FW04896GTYN",
+ partType: "WINDSHIELD",
+ recalibrationType: "STATIC",
+ requiresCapabilityQuestions: false,
+ requiresRecalibration: true,
+ salesTax: 63.86,
+ sellingPrice: 791.46,
+ },
+ ],
+ supportingItems: null,
+ vaps: null,
+ serverData: null,
+ promos: null,
+ },
+ payment: {
+ isInsurance: null,
+ insuranceCoverage: {
+ isVerified: null,
+ coverageStatus: null,
+ coverageType: null,
+ coverageVerificationType: null,
+ },
+ parentAccountNumber: 0,
+ billToAccountNumber: null,
+ isPia: null,
+ piaType: null,
+ inactivePromos: null,
+ paypalToken: null,
+ nextGenSettledAmount: 0,
+ ccToken: {
+ subscriptionId: null,
+ expMonth: null,
+ expYear: null,
+ cardType: null,
+ billToPostalCode: null,
+ billToFirstName: null,
+ billToLastName: null,
+ referenceNumber: null,
+ authCode: null,
+ transactionId: null,
+ transReferenceNumber: null,
+ lastFour: null,
+ },
+ },
+ policy: {
+ currentDeductible: 0,
+ policyNumber: null,
+ isItac: false,
+ additionalAuthFlag: null,
+ isNoComp: false,
+ insuranceCompanyName: null,
+ },
+ schedule: {
+ date: null,
+ startTime: null,
+ endTime: null,
+ routeCode: null,
+ jobMaxMinutes: null,
+ jobMinMinutes: null,
+ },
+ externalParameterServiceZip: {
+ zipCode: null,
+ emailAddress: null,
+ },
+ externalParameterState: { isExternalParameter: false },
+ };
+}
+
+function applyMockStoreDataToGetters() {
+ store.getters = {
+ vehicle: mockStoreData.vehicle,
+ };
+ store.state.order = mockStoreData;
+ store.state.applicationUser.experiments = mockExperimentSettings;
+}
+
+async function mockDispatchStoreAction(actionName) {
+ return mockStoreActionData[actionName];
+}
+
+jest.mock("@/mixins/base-mixin.js", () => ({
+ methods: {
+ dispatchStoreAction: jest.fn(),
+ dispatchStoreActionWithLogging: jest.fn().mockImplementation(mockDispatchStoreAction),
+ },
+}));
+
+jest.mock("@/helpers/cms-content-helper", () => ({
+ fetchCmsContentForPage: () => Promise.resolve("content"),
+}));
+
+jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({
+ saveSession: jest.fn(),
+}));
+
+jest.mock("@/helpers/heritage-integration/cookie-helper", () => ({
+ deleteFunnelCookie: jest.fn(),
+ getFunnelCookie: jest.fn(),
+}));
+
+router.navigateWithoutSaving = jest.fn();
+router.navigateWithSaving = jest.fn();
+
+// Tests
+describe("return-user.vue", () => {
+ beforeEach(() => {
+ resetMockStoreData();
+ jest.clearAllMocks();
+ });
+
+ describe("Test prerequisites are valid and child components are rendered", () => {
+ test("expect pagePrerequisites are valid to be called", () => {
+ // Arrange
+ const wrapper = setupMocks({});
+
+ applyMockStoreDataToGetters();
+
+ // Act
+ const pagePrerequisitesSpy = jest.spyOn(wrapper.vm, "arePagePrerequisitesValid");
+
+ wrapper.vm.arePagePrerequisitesValid();
+
+ // Assert
+ expect(pagePrerequisitesSpy).toBeCalled();
+ expect(getFunnelCookie).toHaveBeenCalled();
+ });
+
+ test("renders child components", () => {
+ const wrapper = setupMocks({});
+
+ expect(wrapper.findComponent(funnelHeader).exists()).toBe(true);
+ expect(wrapper.findComponent(funnelSubHeader).exists()).toBe(true);
+ expect(wrapper.findComponent(navbar).exists()).toBe(true);
+ });
+ });
+
+ describe("Navigation", () => {
+ test("Check forwardButtonAction is working", async () => {
+ // Arrange
+ const wrapper = setupMocks({});
+ // Act
+
+ await wrapper.vm.forwardButtonAction();
+
+ // Assert
+ expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith(
+ navigationScenarios.CLICKED_FORWARD,
+ wrapper.vm.$route
+ );
+ });
+ test("expect functions in startOver to be called", async () => {
+ //Arrange
+ const wrapper = setupMocks({});
+
+ // Act
+ const dispatchStoreActionSpy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
+
+ await wrapper.vm.$nextTick();
+ await wrapper.vm.startOver();
+
+ // Assert
+ expect(wrapper.vm.$router.navigateWithoutSaving).toBeCalledWith(
+ navigationScenarios.CLICKED_FORWARD,
+ wrapper.vm.$route
+ );
+
+ expect(dispatchStoreActionSpy).toHaveBeenCalledWith(storeActions.RESET_STATE);
+ expect(deleteFunnelCookie).toHaveBeenCalled();
+ });
+ });
+});
+
+function setupMocks({ customMountOptions }) {
+ const route = { query: { fmgPage: "return-user" }, params: {} };
+
+ baseMixin.methods.ResetExternalParamsAndHideModal = jest.fn();
+
+ const mountOptions = getMountOptions({
+ ...customMountOptions,
+ route: route,
+ });
+
+ mountOptions.global.mocks["$store"] = store;
+ mountOptions.global.mocks["$router"] = router;
+ baseMixin.methods.isFormValid = jest.fn().mockReturnValue(true);
+ mountOptions["attachTo"] = document.body;
+
+ const wrapper = shallowMount(returnUser, mountOptions, {
+ stubs: {
+ Form,
+ funnelHeader,
+ funnelSubHeader,
+ navbar,
+ loadingModal: true,
+ buttonMain,
+ },
+ });
+
+ return wrapper;
+}
diff --git a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
index 84087cb6e..d88bd53e2 100644
--- a/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
+++ b/src/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue
@@ -241,57 +241,46 @@ export default {
this.displayMismatchStateAndZipAlert = false;
},
async setMobileLocation() {
- if (
- this.internalModel.addressQuestions.zipCode !==
- this.modelValue.addressQuestions.zipCode
- ) {
- this.resetAlerts();
- // Validate the Zip Code
- const zipCodeData = await this.getZipCodeData(
- this.internalModel.addressQuestions.zipCode,
+ this.resetAlerts();
+ // Validate the Zip Code
+ const zipCodeData = await this.getZipCodeData(
+ this.internalModel.addressQuestions.zipCode,
+ "service-location"
+ );
+
+ if (!zipCodeData.isValid) {
+ this.displayInvalidZipAlert = true;
+ this.resetModalButtonStyle();
+ } else if (zipCodeData.state != this.internalModel.addressQuestions.state) {
+ this.displayMismatchStateAndZipAlert = true;
+ this.resetModalButtonStyle();
+ } else {
+ // retrieve mobile fee part
+ const serviceZipCode = this.internalModel.addressQuestions.zipCode;
+ const mobileFeePart = await getPricedMobileFeePart(
+ serviceZipCode,
"service-location"
);
- if (!zipCodeData.isValid) {
- this.displayInvalidZipAlert = true;
- this.resetModalButtonStyle();
- } else if (zipCodeData.state != this.internalModel.addressQuestions.state) {
- this.displayMismatchStateAndZipAlert = true;
- this.resetModalButtonStyle();
- } else {
- // retrieve mobile fee part
- const serviceZipCode = this.internalModel.addressQuestions.zipCode;
- const mobileFeePart = await getPricedMobileFeePart(
- serviceZipCode,
- "service-location"
- );
+ // retrieve serviceability details
+ const serviceabilityDetails = await getServiceabilityDetails(
+ serviceZipCode,
+ null,
+ "service-location"
+ );
- // retrieve serviceability details
- const serviceabilityDetails = await getServiceabilityDetails(
- serviceZipCode,
- null,
- "service-location"
- );
+ const billToAccountNumber = await getBillToAccountNumber(
+ this.internalModel.zipCodeCtu
+ );
- const billToAccountNumber = await getBillToAccountNumber(
- this.internalModel.zipCodeCtu
- );
+ // update content related to service zip code
+ this.$emit("updated-mobile-fee-part", mobileFeePart);
+ this.$emit("updated-serviceability", serviceabilityDetails.data);
+ this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
+ this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu);
+ this.$emit("updated-bill-to-account-number", billToAccountNumber);
- // update content related to service zip code
- this.$emit("updated-mobile-fee-part", mobileFeePart);
- this.$emit("updated-serviceability", serviceabilityDetails.data);
- this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
- this.$emit("updated-mobile-ctu", zipCodeData.zipCodeCtu);
- this.$emit("updated-bill-to-account-number", billToAccountNumber);
-
- // update the page level model
- this.$emit("update:modelValue", this.internalModel);
-
- //Page advance to Schedule page
- this.$emit("mobileLocationSelected");
- }
- } else {
- // Update the page level model
+ // update the page level model
this.$emit("update:modelValue", this.internalModel);
//Page advance to Schedule page
diff --git a/src/layouts/service-location/service-location.spec.js b/src/layouts/service-location/service-location.spec.js
index 6333082ec..54f28a89c 100644
--- a/src/layouts/service-location/service-location.spec.js
+++ b/src/layouts/service-location/service-location.spec.js
@@ -7,6 +7,7 @@ import { getMountOptions } from "@/helpers/unit-test-helper";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
+import { experimentSettings } from "@/constants/experiments";
// Define Mocks
jest.mock("@/helpers/cms-content-helper", () => ({
@@ -199,6 +200,9 @@ beforeEach(() => {
zipCode: "43054",
},
},
+ experimentSettings: {
+ settingName: experimentSettings.DISPLAY_MSR,
+ },
};
});
diff --git a/src/layouts/service-location/service-location.vue b/src/layouts/service-location/service-location.vue
index 71bfa4b01..9addea705 100644
--- a/src/layouts/service-location/service-location.vue
+++ b/src/layouts/service-location/service-location.vue
@@ -139,6 +139,8 @@ import contentGroupModal from "@/fmg-components/content-group-modal/content-grou
// Supporting files
import baseMixin from "@/mixins/base-mixin.js";
+import experimentMixin from "@/mixins/experiment-mixin.js";
+import { experimentSettings } from "@/constants/experiments";
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
@@ -151,6 +153,7 @@ import {
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { applicationConfig } from "@/constants/application-config";
import { Provider } from "@/layouts/service-location/classes/provider";
+import { partNumberStrings } from "@/constants/part-number-strings";
import store from "@/store";
@@ -159,7 +162,6 @@ import { defineRule } from "vee-validate";
import { errorMessages } from "@/constants/error-messages";
const MOBILE_FEE_PART_TYPE = "MOBILE FEE";
-const MOBILE_STATIC_RECAL_FEE_PART_NUMBER = "RECAL MOBILE";
// DEFINE VALIDATION RULES
defineRule("mobile-location-required", (value) => {
@@ -319,11 +321,19 @@ export default {
},
isMobileStaticRecalibrationApplicable() {
return (
+ this.displayMSR &&
this.isVehicleMobileStaticRecalibrationApplicable &&
- this.mobileFeePart?.partNumber == MOBILE_STATIC_RECAL_FEE_PART_NUMBER &&
+ this.mobileFeePart?.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE &&
(this.isInsurance ? this.mobileFeePart?.isInsurable : true)
);
},
+ displayMSR() {
+ return (
+ experimentMixin.methods
+ .getSettingValue(experimentSettings.DISPLAY_MSR)
+ ?.toLowerCase() === "true"
+ );
+ },
mobileFeeApplies() {
if (
this.mobileFeePart?.laborAmount > 0 ||
diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue
index 7cce1c120..6e9c4b198 100644
--- a/src/layouts/vehicle-damage/vehicle-damage.vue
+++ b/src/layouts/vehicle-damage/vehicle-damage.vue
@@ -102,6 +102,7 @@ import { routerParams } from "@/router/router-constants/router-params";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
import { nextTick } from "vue";
+import { getBoolFromString } from "@/helpers/boolean-helper";
// DEFINE VALIDATION RULES
defineRule("replace-options-required", required(errorMessages.REPLACE_OPTIONS_REQUIRED));
@@ -622,7 +623,7 @@ export default {
);
},
shouldDisplayVehicleChangeAlert() {
- return eval(window.history.state.displayVehicleChangeAlert);
+ return getBoolFromString(window.history.state.displayVehicleChangeAlert);
},
shouldHideBackButton() {
return this.$store.getters.requiresVerifiedRedirecting;
diff --git a/src/layouts/vehicle-parts/vehicle-parts.vue b/src/layouts/vehicle-parts/vehicle-parts.vue
index 43f66c376..4b68007f9 100644
--- a/src/layouts/vehicle-parts/vehicle-parts.vue
+++ b/src/layouts/vehicle-parts/vehicle-parts.vue
@@ -94,10 +94,8 @@ export default {
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
- // turned off Save Your Progress for 1/23/25 release
- // to restore, uncomment line below
- // vm.showSaveProgressModal = !(emailFromStore?.length > 0);
-
+ vm.showSaveProgressModal = !(emailFromStore?.length > 0);
+
// Glass Part Question dynamic component
Object.keys(vm.$refs)
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
diff --git a/src/layouts/vehicle/vehicle.vue b/src/layouts/vehicle/vehicle.vue
index d23588d37..79fad6313 100644
--- a/src/layouts/vehicle/vehicle.vue
+++ b/src/layouts/vehicle/vehicle.vue
@@ -80,7 +80,11 @@ import vehicleQuestion from "@/layouts/vehicle/vehicle-question/vehicle-question
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { experimentUniverses } from "@/constants/experiments";
-import { getSessionKeyValue, getUserIdValue } from "@/helpers/heritage-integration/cookie-helper";
+import {
+ getSessionKeyValue,
+ getUserIdValue,
+ getDeviceIdValue,
+} from "@/helpers/heritage-integration/cookie-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { Form, defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
@@ -186,11 +190,12 @@ export default {
storeActions.LOG_EXPERIMENT_EXPOSURE,
{
userId: getUserIdValue(),
+ deviceId: getDeviceIdValue(),
sessionKey: getSessionKeyValue(),
- pageName: to.query.fmgPage,
+ pageName: "vehicle-logExposure", //to.query.fmgPage,
experiment: experimentForLogging,
},
- "vehicle",
+ "vehicle-logExposure",
false
);
}
diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js
index 6f7f67c6f..9bb8f0cda 100644
--- a/src/mixins/analytics-mixin.js
+++ b/src/mixins/analytics-mixin.js
@@ -712,24 +712,19 @@ export default {
return !areAllSessionCookiesSet();
},
- async validateSession() {
- // The noSession function checks the cookies related to analytics logging(sid). it is not the funnel info cookie.
- // The sid cookie for analytics will expire every 30 minutes and get recreated in initSession. If this happens
- // and we also have the funnel cookie present, that indicates they have an existing session that is now expired
- // so route them to the return user page.
+ // sessionExpired is true when one of the analytics cookies(sid, dxdev) has expired but we still have the vehicle year in vuex
+ sessionExpired() {
const fromHeritage = getQuerystringParameter(queryStrings.FROM_HERITAGE) === "true";
- const funnelCookieLastTouched = getFunnelCookie()?.LastTouched;
- if (
- this.noSession() &&
- !fromHeritage &&
- funnelCookieLastTouched !== null &&
- funnelCookieLastTouched !== undefined
- ) {
- await this.initSession();
- router.push({
- path: "/",
- query: { fmgPage: fmgPageValues.RETURN_USER },
- });
+ if (this.noSession() && !fromHeritage && store.getters.order.vehicle?.year > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ async validateSession() {
+ // do not init session if it is expired. let the click event on nav-bar handle session expired logic
+ if (this.sessionExpired()) {
return;
}
diff --git a/src/router/index.js b/src/router/index.js
index d956af773..918688a3c 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -6,7 +6,7 @@ import { lazyLoadComponent } from "@/router/dynamic-routing/component-loader.js"
import { routingTable } from "@/router/router-constants/routing-table.js";
import { globalEvents, globalEventTypes } from "@/constants/events";
import { queryStrings } from "@/constants/query-strings";
-import { getQuerystringParameter } from "@/helpers/querystring-helper";
+import { getQuerystringParameter, buildQuerystringObject } from "@/helpers/querystring-helper";
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
import { fmgPageValues, funnelStartPageName } from "@/router/router-constants/fmgPage-values";
@@ -38,6 +38,7 @@ import { applicationConfig } from "../constants/application-config";
import { shouldStripPromoQueryString } from "@/helpers/promotions-helper";
import bailout from "@/layouts/bailout/bailout";
import { nextTick } from "vue";
+import { getBoolFromString } from "@/helpers/boolean-helper";
const routes = [
{
@@ -58,6 +59,11 @@ const routes = [
await analyticsMixin.methods.validateSession();
+ // after session is validated, remove the fromHeritage querystring if it exists so session expiration works
+ if (to.query) {
+ delete to.query[queryStrings.FROM_HERITAGE];
+ }
+
if (getFunnelCookie()?.SuppressConceptFunnel) {
log(" --go to heritage suppressConceptFunnel: ");
await navigateToHeritageFunnel({ shouldSaveSession: false });
@@ -95,27 +101,24 @@ const routes = [
}
// On entering the funnel "fresh", read cookie information, decide what to do next.
else if (from.redirectedFrom === undefined || fromReturnUser) {
- // if entering the funnel from the content site, check and see if there is already a funnel cookie.
+ // if entering the funnel from the content site, check and see if there is already a vehicle year in vuex.
// if so, send them to return-user page.
- const funnelCookieLastTouched = getFunnelCookie()?.LastTouched;
if (
fromContentSite &&
- funnelCookieLastTouched !== null &&
- funnelCookieLastTouched !== undefined &&
- !toReturnUserPage
+ !toReturnUserPage &&
+ store.getters.order.vehicle?.year > 0
) {
log(" --from content site navigate to return user");
var qso = {
fmgPage: fmgPageValues.RETURN_USER,
};
- const lg = getQuerystringParameter(queryStrings.LOG);
- if (lg) {
- qso[queryStrings.LOG] = true;
- }
+
+ const newQueryString = buildQuerystringObject(qso, true);
+ log(" -- returnUser add querystring: " + JSON.stringify(newQueryString));
router.push({
path: "/",
- query: Object.assign({}, qso),
+ query: Object.assign({}, newQueryString),
});
return;
}
@@ -173,8 +176,8 @@ const routes = [
// clear part related state because heritage selected a new vehicle
if (
to.query.fmgPage === fmgPageValues.VEHICLE &&
- eval(getFunnelCookie()?.HasDelayedClaimRegistration &&
- !fromReturnUser)
+ getBoolFromString(getFunnelCookie()?.HasDelayedClaimRegistration) &&
+ !fromReturnUser
) {
store.commit(storeMutations.RESET_GLASS_PARTS_STATE);
}
@@ -182,7 +185,7 @@ const routes = [
// if coming from the return user page, clear the destination page so implicit navigation runs
log(" --to.query ", JSON.stringify(to.query));
if (fromReturnUser && to.query) {
- log( " --clear to.query");
+ log(" --clear to.query");
delete to.query[queryStrings.FMG_PAGE];
//to.query[queryStrings.FMG_PAGE] = "";
@@ -422,7 +425,7 @@ router.afterEach(async (to, from) => {
store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name);
// If saving on navigation is requested, check for saved SessionId or EmailAddress to determine if saving is appropriate
- if (eval(window.history.state.isSavingNavigation)) {
+ if (getBoolFromString(window.history.state.isSavingNavigation)) {
if (
store.getters.applicationUser.savedSessionId ||
store.getters.order.customer?.emailAddress
@@ -566,7 +569,7 @@ async function navigate(
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
const logQs = getQuerystringParameter(queryStrings.LOG);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, logQs, false);
-
+
log("------------- router index.js navigate start -----------------");
log(" --scenario: ", scenario);
log(" --isSavingNavigation: ", isSavingNavigation);
@@ -631,7 +634,7 @@ function getNavigationMap(scenario, currentRoute) {
function log(message, data) {
const log = getQuerystringParameter(queryStrings.LOG);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_LOGGING_OPTION, log, false);
-
+
data = data ?? "";
const outData = typeof data === "object" ? JSON.stringify(data) : data;
@@ -794,7 +797,7 @@ async function runExperiments(nextPage) {
await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.RUN_EXPERIMENTS_FOR_TRIGGER,
{
- userId: getDeviceIdValue(),
+ deviceId: getDeviceIdValue(),
triggerEvent: experimentTriggers.SITE_ENTRY,
triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE,
},
@@ -805,9 +808,9 @@ async function runExperiments(nextPage) {
await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.RUN_EXPERIMENTS_FOR_TRIGGER,
{
- userId: getDeviceIdValue(),
+ deviceId: getDeviceIdValue(),
triggerEvent: experimentTriggers.PAGE_ENTRY,
- triggerValue: nextPage,
+ triggerValue: nextPage == "vehicle" ? "vehicle-pageEntry" : nextPage,
},
nextPage
);
diff --git a/src/store/index.js b/src/store/index.js
index 5a674b317..77a1f1e95 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1252,7 +1252,7 @@ export const actions = {
// Analytics Actions
logExperimentExposure(
context,
- { payload: { userId, sessionKey, pageName, experiment }, pageNameToLog }
+ { payload: { userId, deviceId, sessionKey, pageName, experiment }, pageNameToLog }
) {
return globalMethods.callHttpClient({
method: endpoints.LogExperimentExposureIfAssigned.method,
@@ -1260,6 +1260,7 @@ export const actions = {
payload: {
experimentForLogging: {
userId: userId,
+ deviceId: deviceId,
experimentUniverseId: experiment.universeId,
experimentUniverseName: experiment.universeName,
experimentTestId: experiment.testId,
@@ -1445,6 +1446,39 @@ export const actions = {
});
},
+ logPartQuestions(
+ context,
+ {
+ eon,
+ ctu,
+ workOrderId,
+ workOrderNumber,
+ carId,
+ glassLocation,
+ partQuestions,
+ userAgent,
+ }
+ ) {
+ var payload = {
+ applicationName: applicationConfig.APPLICATION_NAME,
+ eon: eon,
+ ctu: ctu,
+ workOrderId: workOrderId,
+ workOrderNumber: workOrderNumber,
+ carId: carId,
+ glassLocation: glassLocation,
+ partQuestions: partQuestions,
+ userAgent: navigator.userAgent
+ };
+
+ return globalMethods
+ .callHttpClient({
+ method: endpoints.LogPartQuestions.method,
+ endpoint: endpoints.LogPartQuestions.url,
+ payload: payload,
+ });
+ },
+
// Misc Actions
setReferralInformation(context, { referralNumber, referralDate, referralCorrelationId, eon }) {
context.commit(storeMutations.UPDATE_REFERRAL_NUMBER, referralNumber);
@@ -1463,7 +1497,7 @@ export const actions = {
async runExperimentsForTrigger(
context,
- { payload: { userId, triggerEvent, triggerValue }, pageNameToLog }
+ { payload: { deviceId, triggerEvent, triggerValue }, pageNameToLog }
) {
if (triggerEvent == experimentTriggers.SITE_ENTRY) {
context.commit(storeMutations.UPDATE_TRIGGERED_SITE_ENTRY, true);
@@ -1471,7 +1505,7 @@ export const actions = {
var payload = {
applicationName: applicationConfig.APPLICATION_NAME,
- userId: userId,
+ deviceId: deviceId,
triggerEvent: triggerEvent,
triggerValue: triggerValue,
experimentOrder: context.getters.experimentOrder,
@@ -1638,10 +1672,10 @@ export const actions = {
var endPoint = `${endpoints.GetMobileFeePart.url}/?serviceType=${serviceType}&facilityType=${facilityType}&parentAccountNumber=${parentAccountNumber}&billToAccountNumber=${billToAccountNumber}&providerNumber=${providerNumber}&isItacOptimized=${isItacOptimized}&zipCode=${zipCode}`;
if (isMobileStaticRecalibrationApplicable) {
- const staticRecalPartNumber = getStaticRecalPartNumber(order.lineItems?.glassParts[0]);
+ const recalPartNumber = getRecalPartNumber(order.lineItems?.glassParts[0]);
const carId = order.vehicle?.carId;
- if (staticRecalPartNumber && carId) {
- endPoint = `${endPoint}&partNumbers=${staticRecalPartNumber}&carId=${carId}`;
+ if (recalPartNumber && carId) {
+ endPoint = `${endPoint}&partNumbers=${recalPartNumber}&carId=${carId}`;
}
}
@@ -3685,9 +3719,11 @@ function saveExternalParameterState(externalParameterState) {
window.sessionStorage.setItem("externalParameterState", JSON.stringify(externalParameterState));
}
-//This function checks if static recalibration is available for the vehicle and returns the part number for it.
-function getStaticRecalPartNumber(glassPartsArray) {
- const recalPart = glassPartsArray.childParts.find((item) => item.partNumber === "RECAL STATIC");
+//This function finds the recalibration part and returns the part number for it.
+function getRecalPartNumber(glassPartsArray) {
+ const recalPart = glassPartsArray.childParts.find(
+ (item) => item.partType === partTypeStrings.ADAS_RECALIBRATION
+ );
if (recalPart) {
return recalPart.partNumber;
} else {