Skip to content

Commit 44619a5

Browse files
authored
Merge pull request #823 from MediaJel/jbjm-add-back-reverted-features
2 parents 98a883a + eea7f6d commit 44619a5

File tree

8 files changed

+164
-1
lines changed

8 files changed

+164
-1
lines changed

src/adapters/ecommerce.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ export default async (tracker: SnowplowTracker): Promise<void> => {
7474
// description: "ecwid is just a test description"
7575
// events-tracked: [{ "value": "transaction", "label": "Transaction" }]
7676
break;
77+
case "evenue":
78+
import("../shared/environment-data-sources/evenue").then(({ default: load }): void => load(tracker));
79+
// description: "evenue is just a test description"
80+
// events-tracked: [{ "value": "transaction", "label": "Transaction" }]
81+
break;
7782
case "foxy":
7883
import("../shared/environment-data-sources/foxy").then(({ default: load }): void => load());
7984
// description: "foxy is just a test description"

src/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { getCustomTags } from "./shared/utils/get-custom-tags";
66
import { datasourceLogger } from "./shared/utils/datasource-logger";
77
import { getAppIdTags } from "./shared/utils/get-appId-tags";
88
import { initializeSessionTracking } from "./shared/utils/session-tracking";
9+
import { createRetailId } from "./shared/utils/retail-id-parser";
910

1011
(async (): Promise<void> => {
1112
try {
@@ -22,16 +23,19 @@ import { initializeSessionTracking } from "./shared/utils/session-tracking";
2223
const matchingOverride = window.overrides.find(
2324
(override) => override.tag === context.appId || override.appId === context.appId,
2425
);
26+
logger.debug(`Using default overrides for appId: ${context.appId}`);
2527
if (matchingOverride) {
2628
overrides = matchingOverride;
2729
}
2830
} else if (typeof window.overrides === "object" && window.overrides !== null) {
2931
// New format: window.overrides is an object with appId properties
3032
if (context.appId && window.overrides[context.appId]) {
3133
overrides = window.overrides[context.appId];
34+
logger.debug(`Using New Array overrides for appId: ${context.appId}`);
3235
} else {
3336
// Backwards compatibility for single object override
3437
overrides = window.overrides;
38+
logger.debug(`Using default single overrides for appId: ${context.appId}`);
3539
}
3640
}
3741
} else {
@@ -40,10 +44,16 @@ import { initializeSessionTracking } from "./shared/utils/session-tracking";
4044
...(context["s3.pv"] ? {} : { "s3.pv": "00000" }),
4145
...(context["s3.tr"] ? {} : { "s3.tr": "00000" }),
4246
};
47+
logger.debug(`Using default fallback overrides for appId: ${context.appId}`);
4348
}
4449

4550
const modifiedContext = { ...context, ...overrides };
4651

52+
if (modifiedContext.enable === "false") {
53+
logger.debug("Tag has been disabled. Reach out to your pixel provider for more information.");
54+
return;
55+
}
56+
4757
logger.debug("MJ Tag Context", modifiedContext);
4858
logger.debug("Integrations In Progress");
4959

@@ -54,6 +64,8 @@ import { initializeSessionTracking } from "./shared/utils/session-tracking";
5464
initializeSessionTracking(modifiedContext);
5565
}
5666

67+
window.parseRetailId = createRetailId;
68+
5769
await import("src/adapters").then(({ default: load }) => load(modifiedContext));
5870
} catch (err) {
5971
const clientError = `An error has occured, please contact your pixel provider: `;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import observable from "../utils/create-events-observable";
2+
import { isTrackerLoaded } from "../sources/utils/is-tracker-loaded";
3+
import { datalayerSource } from "../sources/google-datalayer-source";
4+
import { TransactionCartItem } from "../types";
5+
import { multiAdapterHandler } from "../utils/adapter-handler";
6+
import { SnowplowTracker } from "../snowplow/types";
7+
8+
const evenueDataSource = (snowplow: SnowplowTracker) => {
9+
const handler = multiAdapterHandler(snowplow);
10+
11+
handler.add("DataLayer Source", () => {
12+
isTrackerLoaded(() => {
13+
datalayerSource((data) => {
14+
if (data.event === "purchase") {
15+
const purchase = data?.ecommerce?.items;
16+
17+
observable.notify({
18+
transactionEvent: {
19+
id: data.transaction_id,
20+
total: parseFloat(data.value) || 0,
21+
tax: 0,
22+
shipping: parseFloat(data.shipping) || 0,
23+
discount: 0,
24+
couponCode: "N/A",
25+
city: "N/A",
26+
state: "N/A",
27+
country: "USA",
28+
currency: "USD",
29+
items:
30+
purchase?.map((item) => {
31+
return {
32+
orderId: data.transaction_id,
33+
sku: item.item_id.toString() || "N/A",
34+
name: item.item_name.toString() || "N/A",
35+
category: item.item_category.toString() || "N/A",
36+
unitPrice: parseFloat(item.price) || 0,
37+
quantity: parseInt(item.quantity) || 1,
38+
currency: "USD",
39+
} as TransactionCartItem;
40+
}) || [],
41+
},
42+
});
43+
}
44+
});
45+
});
46+
});
47+
48+
handler.execute();
49+
};
50+
51+
export default evenueDataSource;

src/shared/environment-data-sources/jane.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const janeDataSource = (snowplow: SnowplowTracker) => {
5858
deliveryAddress = {},
5959
salesTax,
6060
storeTax,
61+
discountTotal,
6162
} = payload.properties;
6263

6364
observable.notify({
@@ -70,6 +71,8 @@ const janeDataSource = (snowplow: SnowplowTracker) => {
7071
city: (deliveryAddress?.city || "N/A").toString(),
7172
state: (deliveryAddress?.state_code || "N/A").toString(),
7273
country: (deliveryAddress?.country_code || "N/A").toString(),
74+
discount: parseFloat(discountTotal || 0),
75+
couponCode: "N/A",
7376
currency: "USD",
7477
items: products.map((product) => {
7578
const { product_id, name, category, unit_price, count } = product;

src/shared/environment-data-sources/magento.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ const magentoDataSource = () => {
3434
city: "N/A",
3535
country: "USA",
3636
currency: "USD",
37+
couponCode: ecommerce.coupon || "N/A",
38+
discount: parseFloat(ecommerce.discount) || 0,
3739
state: "N/A",
3840
items: ecommerce.items.map((item: any) => {
3941
return {

src/shared/interface.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { TransactionEvent, CartEvent, SignupParams } from "./snowplow/types";
2-
import { QueryStringContext, RegisterThirdPartyTagsInput } from "./types";
2+
import { QueryStringContext, RegisterThirdPartyTagsInput, retailIdentifier } from "./types";
33

44
export {};
55

@@ -27,5 +27,7 @@ declare global {
2727
gtmDataLayer: any;
2828
registerThirdPartyTags: (input: RegisterThirdPartyTagsInput) => void;
2929
overrides: QueryStringContext;
30+
parseRetailId: (retail: retailIdentifier) => void;
31+
navigation: any;
3032
}
3133
}

src/shared/types.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,21 @@ export type SignupParams = {
7474
advertiser: string;
7575
};
7676

77+
export interface retailIdentifier {
78+
id: {
79+
/**
80+
* The name of the retail identifier, used to create a URL parameter.
81+
*/
82+
retailId: string;
83+
/**
84+
* An array of CSS selectors or element IDs to poll for the retail identifier.
85+
* These elements should be present on the page to ensure the retail ID is applied correctly.
86+
*/
87+
element: string[];
88+
fn?: () => void;
89+
}[];
90+
}
91+
7792
export type SnowplowParams = {
7893
appId: string;
7994
mediajelAppId?: string;
@@ -152,6 +167,10 @@ export type DstillerySegmentParams = {
152167
"s3.tr": string;
153168
};
154169

170+
export type enableTagParam = {
171+
enable: "true" | "false";
172+
};
173+
155174
export type SegmentParams = LiquidmSegmentParams & NexxenSegmentParams & DstillerySegmentParams;
156175

157176
export type DatasourceTrackerParam = {
@@ -167,6 +186,7 @@ export type QueryStringParams = Partial<TransactionParams> &
167186
BingAdsPluginParams &
168187
SnowplowParams &
169188
SegmentParams &
189+
enableTagParam &
170190
DatasourceTrackerParam & { sdkUrl: string };
171191

172192
// Params available to the tag's query string
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { pollForElement } from "../sources/utils/poll-for-element";
2+
import { retailIdentifier } from "../types";
3+
/**
4+
* Dynamically parses a retail ID on the site url by polling for specific elements present on the checkout page.
5+
* @param {retailIdentifier} retail - The retail identifier object containing the elements to poll.
6+
* Please use a specific element id on a page to ascertain that the page should have a retail ID.
7+
* ! If not used correctly, we could append a retail ID to every page.
8+
* @example
9+
* const ecommerce = {
10+
* id: [
11+
* {
12+
* retailId: "California",
13+
* element: [".ca-element", "#california-element", "[data-state='CA-element']"],
14+
* fn: () => { console.log("Retail ID applied for California"); }
15+
* },
16+
* {
17+
* retailId: "New York",
18+
* element: [".ny-element", "#ny-element", "[data-state='NY-element']"],
19+
* fn: () => { console.log("Retail ID applied for New York"); }
20+
* },
21+
* ],
22+
* };
23+
* createRetailId(ecommerce);
24+
*/
25+
export const createRetailId = (retail: retailIdentifier) => {
26+
const { id } = retail;
27+
28+
const parseRetailId = () => {
29+
id.forEach((retail) => {
30+
pollForElement(retail.element, () => {
31+
if (!retail.element) return;
32+
const baseUrl = window.location.href;
33+
const url = new URL(baseUrl);
34+
const urlId = retail.retailId.replace(/\s+/g, "").toLowerCase();
35+
retail.element.forEach((elementSelector) => {
36+
const element = document.querySelector(elementSelector);
37+
if (element) {
38+
console.log(`Element detected for retail ID "${retail.retailId}": ${elementSelector}`);
39+
}
40+
});
41+
42+
url.searchParams.set("retailId", urlId);
43+
window.history.replaceState({}, "", url.toString());
44+
45+
if (retail.fn) {
46+
retail.fn();
47+
}
48+
});
49+
});
50+
};
51+
52+
parseRetailId();
53+
54+
const checkUrlChange = () => {
55+
window.navigation.addEventListener("navigate", () => {
56+
let previousUrl = sessionStorage.getItem("previousUrl");
57+
const currentUrl = window.location.href;
58+
sessionStorage.setItem("currentUrl", currentUrl);
59+
60+
if (currentUrl !== previousUrl) {
61+
sessionStorage.setItem("previousUrl", currentUrl);
62+
parseRetailId();
63+
}
64+
});
65+
};
66+
67+
setInterval(checkUrlChange, 1000);
68+
};

0 commit comments

Comments
 (0)