diff --git a/src/constants/application-config.js b/src/constants/application-config.js
index a72b306d3..6a747617f 100644
--- a/src/constants/application-config.js
+++ b/src/constants/application-config.js
@@ -31,6 +31,7 @@ const applicationConfig = {
"https://outlook.office.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent",
FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging",
AFFILIATE_COOKIE_CONTAINING_NAME: "_Track",
+ COOKIE_NAME_LENGTH_MAX_LIMIT: 44,
};
export { applicationConfig };
diff --git a/src/constants/cookie-names.js b/src/constants/cookie-names.js
index d62934cf5..72e6168fb 100644
--- a/src/constants/cookie-names.js
+++ b/src/constants/cookie-names.js
@@ -10,6 +10,9 @@ const cookieNames = {
DXDEV: "dxdev",
SESSION_ID: "sid",
SESSION_KEY: "skey",
+
+ //Commission Junction Cookie
+ CJE: "cje",
};
const cookieExpirations = {
@@ -17,6 +20,8 @@ const cookieExpirations = {
DXDEV: convertToSeconds({ years: 1 }),
FUNNEL_USER_ID: convertToSeconds({ weeks: 1 }),
FUNNEL_SESSION_KEY: convertToSeconds({ minutes: 30 }),
+ CJE: convertToSeconds({ days: 395 }),
+ NON_CJ: convertToSeconds({ days: 100000 }),
};
export { cookieNames, cookieExpirations };
diff --git a/src/constants/query-strings.js b/src/constants/query-strings.js
index 8d55424a9..9fb379836 100644
--- a/src/constants/query-strings.js
+++ b/src/constants/query-strings.js
@@ -37,6 +37,13 @@ const queryStrings = {
SERVICE_PACKAGE: "servicepackage",
NUMBER_OF_CHIPS: "numberofchips",
LOG: "log",
+ UTM_SOURCE: "_source",
+ UTM_MEDIUM: "_medium",
+ UTM_CAMPAIGN: "_campaign",
+ CJ_EVENT: "cjevent",
+ CJUNCTION: "cjunction",
+ ORGANIC: "organic",
+ ORGANIC_SOCIAL: "organic_social",
};
export { queryStrings };
diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue
index 495973144..9e5a43bd6 100644
--- a/src/fmg-components/cart/cart.vue
+++ b/src/fmg-components/cart/cart.vue
@@ -140,7 +140,7 @@
Promo code {{ promoCode }} applied
@@ -184,6 +184,7 @@ export default {
allowItemRemoval: Boolean,
recyclingModalCmsWidgetName: String,
showAsPaid: Boolean,
+ isInsurance: Boolean,
insuranceDeductible: Number,
insuranceCompanyName: String,
showInsuranceCoverageAs: String,
@@ -283,6 +284,7 @@ export default {
(lineItemsToKeep) => lineItemsToKeep.cartItemType != cartItemType
);
},
+
getPromoCodeList() {
if (this.$refs["promoModalQuestion"]) {
return this.$refs["promoModalQuestion"].getPromoCodeList();
@@ -299,6 +301,14 @@ export default {
this.$emit("update:modelValue", newValue);
},
},
+ lineItemsWithoutRecal() {
+ if (!this.lineItems || this.lineItems.length < 1) return;
+ const lineItemsCopy = deepClone(this.lineItems);
+ lineItemsCopy.supportingItems = baseMixin.methods.filterOutRecalibration(
+ lineItemsCopy.supportingItems
+ );
+ return lineItemsCopy;
+ },
showCoverageAsPending() {
return this.showInsuranceCoverageAs === coverageStatus.PENDING;
},
@@ -427,7 +437,14 @@ export default {
packagePrice() {
let packagePrice = 0;
- if (!this.showCoverageAsVerified && !this.showCoverageAsPending) {
+ if (!this.isInsurance) {
+ // CASH ONLY
+ packagePrice = baseMixin.methods.getTierOnePackagePrice(
+ baseMixin.methods.filterOutFees(
+ baseMixin.methods.filterOutRecalibration(this.availableLineItems)
+ )
+ );
+ } else if (!this.showCoverageAsVerified && !this.showCoverageAsPending) {
packagePrice = baseMixin.methods.getTierOnePackagePrice(
baseMixin.methods.filterOutFees(this.availableLineItems)
);
@@ -916,8 +933,6 @@ export default {
promoCartItems() {
const promoCartItems = [];
- // clone the promos array
- const promosClone = deepClone(this.promo);
// get unique promo codes
const uniquePromoCodes = [
...new Set(
@@ -983,16 +998,23 @@ export default {
return this.getCmsContent("SubtotalTextWidget", "Text");
},
subTotal() {
- return baseMixin.methods.getSubTotal(this.lineItems);
+ if (!this.lineItems || this.lineItems.length < 1) return;
+ return this.isInsurance
+ ? baseMixin.methods.getSubTotal(this.lineItems)
+ : baseMixin.methods.getSubTotal(this.lineItemsWithoutRecal);
},
salesTax() {
- return baseMixin.methods.getSalesTax(this.lineItems);
+ if (!this.lineItems || this.lineItems.length < 1) return;
+ return this.isInsurance
+ ? baseMixin.methods.getSalesTax(this.lineItems)
+ : baseMixin.methods.getSalesTax(this.lineItemsWithoutRecal);
},
amountDue() {
- if (this.showAsPaid) {
- return 0;
- }
- return baseMixin.methods.getAmountDue(this.lineItems);
+ if (!this.lineItems || this.lineItems.length < 1) return;
+ if (this.showAsPaid) return 0;
+ return this.isInsurance
+ ? baseMixin.methods.getAmountDue(this.lineItems)
+ : baseMixin.methods.getAmountDue(this.lineItemsWithoutRecal);
},
amountPaid() {
if (!this.showAsPaid) {
diff --git a/src/helpers/heritage-integration/cookie-helper.js b/src/helpers/heritage-integration/cookie-helper.js
index 1b7b551ca..0bd4ae563 100644
--- a/src/helpers/heritage-integration/cookie-helper.js
+++ b/src/helpers/heritage-integration/cookie-helper.js
@@ -1,7 +1,9 @@
import { cookieNames, cookieExpirations } from "@/constants/cookie-names";
import store from "@/store";
import { applicationConfig } from "@/constants/application-config";
-
+import { getQuerystringParameter } from "@/helpers/querystring-helper";
+import { queryStrings } from "@/constants/query-strings";
+//import { cookieParameters } from "@/constants/cookie-parameters";
/*
Will update the cookie if present, or create a new one if not.
*/
@@ -221,6 +223,79 @@ export function getAffiliateCookies() {
return affiliateCookies;
}
+export function setupAdvertiserTracking() {
+ var utmSource = getQuerystringParameter(queryStrings.UTM_SOURCE);
+ var utmMedium = getQuerystringParameter(queryStrings.UTM_MEDIUM);
+ var utmCampaign = getQuerystringParameter(queryStrings.UTM_CAMPAIGN);
+ const cjEvent = getQuerystringParameter(queryStrings.CJ_EVENT);
+ // helper check for if an object is defined (but maybe falsey)
+ const isDefined = (x) => x !== null && x !== undefined;
+ if (isDefined(cjEvent) != "") {
+ const cjeCookieName = cookieNames.CJE;
+ if (!isCookieSet(cjeCookieName)) {
+ createCJEventCookie(cjEvent, cjeCookieName);
+ }
+ }
+ //Firstly, Can't continue without utm-source or utm-medium.
+ //Secondly, Ignore the advertiser for CJ-affiliate-click and Email-click.
+ if (
+ !isDefined(utmSource) ||
+ isDefined(utmSource) == "" ||
+ !isDefined(utmMedium) ||
+ isDefined(utmMedium) == "" ||
+ utmSource?.toLowerCase() == queryStrings.CJUNCTION ||
+ utmMedium?.toLowerCase() == queryStrings.EMAIL ||
+ utmMedium?.toLowerCase() == queryStrings.ORGANIC ||
+ utmMedium?.toLowerCase() == queryStrings.ORGANIC_SOCIAL
+ ) {
+ return;
+ }
+ //UTC date time format yyyy-MM-dd/HH:mm:ss
+ const currentDateTime = new Date().toISOString().replace(/T/, "/").replace(/\..+/, "");
+
+ //Format cookie, by removing spaces and special characters.
+ utmSource = FormatCookieElementName(utmSource);
+ utmMedium = FormatCookieElementName(utmMedium);
+ utmCampaign = FormatCookieElementName(utmCampaign);
+
+ var cookieNameBuilder = utmSource + "_" + utmMedium;
+ //Since utmCampaign is optional, ignore the rest.
+ if (isDefined(utmCampaign) && utmCampaign != "") {
+ cookieNameBuilder = cookieNameBuilder + "_" + utmCampaign;
+ }
+ const cookieName =
+ (cookieNameBuilder.length > applicationConfig.COOKIE_NAME_LENGTH_MAX_LIMIT
+ ? cookieNameBuilder.substring(0, applicationConfig.COOKIE_NAME_LENGTH_MAX_LIMIT)
+ : cookieNameBuilder) + applicationConfig.AFFILIATE_COOKIE_CONTAINING_NAME;
+
+ if (!isCookieSet(cookieName)) {
+ const values = [
+ `utm_source= ${utmSource}`,
+ `utm_medium= ${utmMedium}`,
+ `utm_campaign= ${utmCampaign}`,
+ `timestamp= ${currentDateTime}`,
+ `tagEvent= ${cjEvent}`,
+ ];
+ let valueString = values.join("&");
+ createOrUpdateCookie(cookieName, valueString, {
+ useDefaultFunnelCookieAttributes: true,
+ maxAge: cookieExpirations.NON_CJ,
+ });
+ } else {
+ const cookieValue = getCookieValueByName(cookieName);
+ if (cookieValue) {
+ let cookieValueObj = convertStringToObject(cookieValue);
+ cookieValueObj.timestamp = currentDateTime; // Update the property
+ // Set the updated cookie
+ const cookieValueString = objectToString(cookieValueObj);
+ createOrUpdateCookie(cookieName, cookieValueString, {
+ useDefaultFunnelCookieAttributes: true,
+ maxAge: cookieExpirations.NON_CJ,
+ });
+ }
+ }
+}
+
/*
===========================
= PRIVATE FUNCTIONS =
@@ -253,7 +328,7 @@ function setFunnelCookieProperties(properties) {
function createOrUpdateCookie(
key,
value = "",
- { useDefaultFunnelCookieAttributes = true, maxAge, isSecure = true }
+ { useDefaultFunnelCookieAttributes = true, maxAge, isSecure = true, crossSiteAccess = false }
) {
let cookieToAdd = `${key}=${value}; `;
@@ -266,6 +341,9 @@ function createOrUpdateCookie(
if (!isNaN(maxAge)) {
cookieToAdd += `max-age=${maxAge};`;
}
+ if (crossSiteAccess && isSecure) {
+ cookieToAdd += `sameSite=None;`;
+ }
document.cookie = cookieToAdd;
}
@@ -315,3 +393,42 @@ function getCookiesContainingName(name) {
}
return matchingCookies;
}
+function createCJEventCookie(cjEvent, cookieName) {
+ createOrUpdateCookie(cookieName, cjEvent, {
+ useDefaultFunnelCookieAttributes: true,
+ maxAge: cookieExpirations.CJE,
+ isSecure: true,
+ crossSiteAccess: true,
+ });
+}
+
+function FormatCookieElementName(cookie) {
+ // Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
+ const problemSymbols = '\\s\\(\\)<>@,;:\\\\/\\[\\]\\?=\\{}"';
+ const otherSymbols = "!#$%^&+\\-*|~`";
+ const symbolsToIgnore = new RegExp("[" + problemSymbols + otherSymbols + "]+", "g");
+
+ return (cookie || "").replace(symbolsToIgnore, ".");
+}
+
+function convertStringToObject(str) {
+ let obj = {};
+ let pairs = str.split("&");
+
+ pairs.forEach((pair) => {
+ let [key, value] = pair.split("=");
+ obj[key] = value;
+ });
+
+ return obj;
+}
+function objectToString(obj) {
+ let str = "";
+ for (let key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
+ str += key + "=" + obj[key] + "&";
+ }
+ }
+ // Remove the trailing '&'
+ return str.slice(0, -1);
+}
diff --git a/src/layouts/payment-method/payment-method.vue b/src/layouts/payment-method/payment-method.vue
index 45c2cbc2e..0edcd9982 100644
--- a/src/layouts/payment-method/payment-method.vue
+++ b/src/layouts/payment-method/payment-method.vue
@@ -30,6 +30,7 @@
pageName="payment-method"
servicePackageOptionsCmsName="ServicePackageTitle"
recyclingModalCmsWidgetName="RecycleModal"
+ :isInsurance="isInsurance"
:insuranceDeductible="currentDeductible"
:insuranceCompanyName="insuranceCompanyName"
:showInsuranceCoverageAs="showInsuranceCoverageAs" />
@@ -530,14 +531,18 @@ export default {
await submitWorkOrder({ pageNameToLog: "payment-method", submitAfterSave: true });
this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_FORWARD,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_PIA_ALERT]: false }
);
} else {
if (this.paymentMethod == paymentMethods.INSURANCE) {
this.dispatchStoreAction(this.storeActions.SAVE_PAYMENT_TYPE, true, false);
this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_INSURANCE,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_PIA_ALERT]: false }
);
} else {
this.setupPia();
@@ -559,14 +564,16 @@ export default {
} catch (error) {
console.log("error: response from pia submit work order:" + error.message);
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
- this.$route.params[routerParams.DISPLAY_PIA_ALERT] = true;
+ this.$route.query[queryStrings.DISPLAY_PIA_ALERT] = true;
return;
}
}
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_PAY_NOW,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_PIA_ALERT]: false }
);
},
hasSubmittedOrder() {
@@ -687,7 +694,7 @@ export default {
shouldDisplayPiaAlert() {
return (
this.$route.query[queryStrings.DISPLAY_PIA_ALERT] ||
- this.$route.params[routerParams.DISPLAY_PIA_ALERT]
+ eval(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 987caf56d..5dc103c68 100644
--- a/src/layouts/payment/payment.vue
+++ b/src/layouts/payment/payment.vue
@@ -747,7 +747,7 @@ export default {
shouldDisplayPiaAlert(payMethod) {
return (
this.$route.query[queryStrings.DISPLAY_PIA_ALERT] === payMethod ||
- this.$route.params[routerParams.DISPLAY_PIA_ALERT] === payMethod
+ eval(window.history.state.displayPiaAlert)
);
},
},
diff --git a/src/layouts/vehicle-damage/vehicle-damage.spec.js b/src/layouts/vehicle-damage/vehicle-damage.spec.js
index b490114da..bc4ab9356 100644
--- a/src/layouts/vehicle-damage/vehicle-damage.spec.js
+++ b/src/layouts/vehicle-damage/vehicle-damage.spec.js
@@ -310,12 +310,11 @@ describe("vehicle-damage.vue", () => {
describe("alert", () => {
test("when displayVehicleChangeAlert router params is true, the alert: 'vehicleChangeAlert' should be rendered", () => {
// Arrange & Act
+ window.history.pushState({ displayVehicleChangeAlert: "true" }, "", "");
const { wrapper } = setupMocks({
mountOptionsMockData: {
route: {
- params: {
- [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true,
- },
+ state: { displayVehicleChangeAlert: true },
},
},
});
@@ -325,21 +324,24 @@ describe("vehicle-damage.vue", () => {
test("when displayVehicleChangeAlert router params is false, the alert: 'vehicleChangeAlert' should not be rendered", () => {
// Arrange & Act
+ window.history.pushState({ displayVehicleChangeAlert: "false" }, "", "");
const { wrapper } = setupMocks({
mountOptionsMockData: {
route: {
- params: {
+ state: {
[routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false,
},
},
},
});
+
// Assert
expect(wrapper.findComponent({ ref: "vehicleChangeAlert" }).exists()).toBe(false);
});
test("when displayVehicleChangeAlert router params is undefined, the alert: 'vehicleChangeAlert' should not be rendered", () => {
// Arrange & Act
+ window.history.pushState({ displayVehicleChangeAlert: "false" }, "", "");
const { wrapper } = setupMocks({
mountOptionsMockData: {
route: {
@@ -850,7 +852,7 @@ function setupMocks({ pageHeaderWidgetHeaderText, mountOptionsMockData, funnelCo
navigateWithSaving: jest.fn(),
},
route: {
- params: {
+ state: {
[routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false,
},
},
diff --git a/src/layouts/vehicle-damage/vehicle-damage.vue b/src/layouts/vehicle-damage/vehicle-damage.vue
index 5744597e4..d22bb9c81 100644
--- a/src/layouts/vehicle-damage/vehicle-damage.vue
+++ b/src/layouts/vehicle-damage/vehicle-damage.vue
@@ -103,6 +103,7 @@ import { errorMessages } from "@/constants/error-messages";
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
+import { routerParams } from "@/router/router-constants/router-params";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin";
@@ -405,20 +406,26 @@ export default {
if (skipVin) {
this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_SKIP_VIN,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
);
} else {
if (store.getters.damage.isRepair) {
this.$router.navigateWithSaving(
this.navigationScenarios
.CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
);
} else {
this.$router.navigateWithSaving(
this.navigationScenarios
.CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
);
}
}
@@ -427,17 +434,23 @@ export default {
else if (store.getters.vehicle.vin) {
this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
);
} else if (skipVin) {
this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_SKIP_VIN,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
);
} else {
this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
- this.$route
+ this.$route,
+ {},
+ { [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
);
}
},
@@ -566,7 +579,7 @@ export default {
);
},
shouldDisplayVehicleChangeAlert() {
- return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
+ return eval(window.history.state.displayVehicleChangeAlert);
},
shouldHideBackButton() {
return this.$store.getters.requiresVerifiedRedirecting;
diff --git a/src/mixins/base-mixin.js b/src/mixins/base-mixin.js
index 1f4f9178b..04ce4c3a5 100644
--- a/src/mixins/base-mixin.js
+++ b/src/mixins/base-mixin.js
@@ -102,6 +102,12 @@ export default {
});
return filteredLineItems;
},
+ filterOutRecalibration(lineItems) {
+ const filteredLineItems = lineItems.filter((item) => {
+ return item.partType != partTypeStrings.RECALIBRATION;
+ });
+ return filteredLineItems;
+ },
getTotalPriceOfAllLineItemsAndChildParts(lineItems, includeTax) {
let totalPrice = 0;
lineItems.forEach((lineItem) => {
diff --git a/src/router/index.js b/src/router/index.js
index 5d09686d1..23751e43d 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -19,6 +19,7 @@ import {
updateSessionIdCookie,
deleteFunnelCookie,
getAffiliateCookies,
+ setupAdvertiserTracking,
} from "@/helpers/heritage-integration/cookie-helper";
import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integration/order-helper";
import {
@@ -103,7 +104,7 @@ const routes = [
if (affiliateCookies != null && affiliateCookies.length > 0) {
store.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies);
}
-
+ setupAdvertiserTracking();
const loadSessionResponse = await loadSessionIfPresent(
to.query.isInsurance != null
? to.query.isInsurance == "true"
@@ -397,6 +398,8 @@ async function navigate(
: (existingPageDataForPage ?? {})
);
+ optionalParams.isSavingNavigation = isSavingNavigation;
+
// add querystring params to the route. if they are already in the store then no need to add them
var queryStringsObject = {
fmgPage: destinationFmgPageValue,
@@ -433,9 +436,7 @@ async function navigate(
router.push({
name: "root",
query: Object.assign(optionalQuery, queryStringsObject),
- state: {
- isSavingNavigation: isSavingNavigation
- }
+ state: optionalParams,
});
} else if (matchingScenarioMap.destinationUrl !== undefined) {
navigateToUrl(matchingScenarioMap.destinationUrl, optionalQuery);