@simplybusiness/services 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/cjs/data/scripts-mock.js +59 -0
- package/dist/cjs/data/scripts-mock.js.map +1 -0
- package/dist/cjs/index.js +20 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/mocks/eventDefinitions.js +46 -0
- package/dist/cjs/mocks/eventDefinitions.js.map +1 -0
- package/dist/cjs/services/airbrake/index.js +23 -0
- package/dist/cjs/services/airbrake/index.js.map +1 -0
- package/dist/cjs/services/index.js +25 -0
- package/dist/cjs/services/index.js.map +1 -0
- package/dist/cjs/services/snowplow/SnowplowContext.js +61 -0
- package/dist/cjs/services/snowplow/SnowplowContext.js.map +1 -0
- package/dist/cjs/services/snowplow/contexts.js +18 -0
- package/dist/cjs/services/snowplow/contexts.js.map +1 -0
- package/dist/cjs/services/snowplow/event-definitions.js +235 -0
- package/dist/cjs/services/snowplow/event-definitions.js.map +1 -0
- package/dist/cjs/services/snowplow/getSnowplowConfig.js +16 -0
- package/dist/cjs/services/snowplow/getSnowplowConfig.js.map +1 -0
- package/dist/cjs/services/snowplow/index.js +138 -0
- package/dist/cjs/services/snowplow/index.js.map +1 -0
- package/dist/cjs/services/snowplow/types.js +6 -0
- package/dist/cjs/services/snowplow/types.js.map +1 -0
- package/dist/cjs/tsconfig.tsbuildinfo +1 -0
- package/dist/cjs/utils/index.js +20 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/cjs/utils/testUtils.js +43 -0
- package/dist/cjs/utils/testUtils.js.map +1 -0
- package/dist/cjs/utils/text.js +13 -0
- package/dist/cjs/utils/text.js.map +1 -0
- package/dist/esm/data/scripts-mock.js +49 -0
- package/dist/esm/data/scripts-mock.js.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/mocks/eventDefinitions.js +36 -0
- package/dist/esm/mocks/eventDefinitions.js.map +1 -0
- package/dist/esm/services/airbrake/index.js +13 -0
- package/dist/esm/services/airbrake/index.js.map +1 -0
- package/dist/esm/services/index.js +8 -0
- package/dist/esm/services/index.js.map +1 -0
- package/dist/esm/services/snowplow/SnowplowContext.js +43 -0
- package/dist/esm/services/snowplow/SnowplowContext.js.map +1 -0
- package/dist/esm/services/snowplow/contexts.js +8 -0
- package/dist/esm/services/snowplow/contexts.js.map +1 -0
- package/dist/esm/services/snowplow/event-definitions.js +240 -0
- package/dist/esm/services/snowplow/event-definitions.js.map +1 -0
- package/dist/esm/services/snowplow/getSnowplowConfig.js +7 -0
- package/dist/esm/services/snowplow/getSnowplowConfig.js.map +1 -0
- package/dist/esm/services/snowplow/index.js +133 -0
- package/dist/esm/services/snowplow/index.js.map +1 -0
- package/dist/esm/services/snowplow/types.js +3 -0
- package/dist/esm/services/snowplow/types.js.map +1 -0
- package/dist/esm/utils/index.js +3 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/utils/testUtils.js +26 -0
- package/dist/esm/utils/testUtils.js.map +1 -0
- package/dist/esm/utils/text.js +3 -0
- package/dist/esm/utils/text.js.map +1 -0
- package/dist/types/data/scripts-mock.d.ts +44 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/mocks/eventDefinitions.d.ts +32 -0
- package/dist/types/services/airbrake/index.d.ts +2 -0
- package/dist/types/services/index.d.ts +5 -0
- package/dist/types/services/snowplow/SnowplowContext.d.ts +14 -0
- package/dist/types/services/snowplow/SnowplowContext.test.d.ts +1 -0
- package/dist/types/services/snowplow/contexts.d.ts +3 -0
- package/dist/types/services/snowplow/contexts.test.d.ts +1 -0
- package/dist/types/services/snowplow/event-definitions.d.ts +18 -0
- package/dist/types/services/snowplow/getSnowplowConfig.d.ts +2 -0
- package/dist/types/services/snowplow/index.d.ts +29 -0
- package/dist/types/services/snowplow/index.test.d.ts +1 -0
- package/dist/types/services/snowplow/types.d.ts +37 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/testUtils.d.ts +7 -0
- package/dist/types/utils/text.d.ts +1 -0
- package/dist/types/utils/text.test.d.ts +1 -0
- package/package.json +86 -0
- package/src/__mocks__/snowplowBrowserTrackerMock.js +6 -0
- package/src/data/scripts-mock.ts +44 -0
- package/src/index.tsx +1 -0
- package/src/mocks/eventDefinitions.ts +39 -0
- package/src/services/airbrake/index.ts +16 -0
- package/src/services/index.tsx +6 -0
- package/src/services/snowplow/SnowplowContext.test.tsx +32 -0
- package/src/services/snowplow/SnowplowContext.tsx +68 -0
- package/src/services/snowplow/contexts.test.ts +42 -0
- package/src/services/snowplow/contexts.ts +14 -0
- package/src/services/snowplow/event-definitions.ts +256 -0
- package/src/services/snowplow/getSnowplowConfig.ts +8 -0
- package/src/services/snowplow/index.test.ts +194 -0
- package/src/services/snowplow/index.ts +163 -0
- package/src/services/snowplow/types.ts +65 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/testUtils.tsx +36 -0
- package/src/utils/text.test.ts +9 -0
- package/src/utils/text.ts +2 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SelfDescribingJson, StructuredEvent } from "@snowplow/browser-tracker";
|
|
2
|
+
import { EventDefinition, TrackingProps } from "./types";
|
|
3
|
+
export type FrontOfficeStructuredEvent = StructuredEvent & {
|
|
4
|
+
serviceChannelIdentifier: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* This class is an abstraction which wraps Snowplow
|
|
8
|
+
* and exposes common methods with other services:
|
|
9
|
+
* - trackEvent : sends a standard payload
|
|
10
|
+
* - trackUnstructEvent : sends a payload for custom schema
|
|
11
|
+
*/
|
|
12
|
+
export declare class Snowplow {
|
|
13
|
+
avalancheTrackerName: string;
|
|
14
|
+
bronzeAvalancheTrackerName: string;
|
|
15
|
+
pvAvalancheTrackerName: string;
|
|
16
|
+
uid: unknown;
|
|
17
|
+
trackPageView: boolean;
|
|
18
|
+
contexts: SelfDescribingJson<Record<string, unknown>>[];
|
|
19
|
+
eventHandlers: Record<string, (params?: Record<string, unknown>) => void>;
|
|
20
|
+
constructor(props?: TrackingProps);
|
|
21
|
+
setContexts(contexts: SelfDescribingJson<Record<string, unknown>>[]): this;
|
|
22
|
+
trackView(): this;
|
|
23
|
+
trackEvent(event: StructuredEvent): Promise<this>;
|
|
24
|
+
trackUnstructEvent(event: SelfDescribingJson<Record<string, unknown>>): Promise<this>;
|
|
25
|
+
addEventHandlers(eventDefinitions: EventDefinition[]): this;
|
|
26
|
+
private addEventHandler;
|
|
27
|
+
private removeEventHandler;
|
|
28
|
+
trigger(name: string, params?: Record<string, unknown>): this;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EventMethod, SelfDescribingJson, StructuredEvent } from "@snowplow/browser-tracker";
|
|
2
|
+
type BaseConfig = {
|
|
3
|
+
appId: string;
|
|
4
|
+
avalancheCollector: string;
|
|
5
|
+
eventMethod: EventMethod;
|
|
6
|
+
trackPageView: boolean;
|
|
7
|
+
includeGAContext: boolean;
|
|
8
|
+
uid?: string;
|
|
9
|
+
postPath?: string;
|
|
10
|
+
};
|
|
11
|
+
export type EnvConfig = BaseConfig & {
|
|
12
|
+
cookieDomain: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
export type TrackingProps = BaseConfig & {
|
|
15
|
+
eventMethod: EventMethod;
|
|
16
|
+
cookieDomain?: string;
|
|
17
|
+
};
|
|
18
|
+
export type ChannelContext = {
|
|
19
|
+
schema: string;
|
|
20
|
+
data: Record<string, string | number>;
|
|
21
|
+
};
|
|
22
|
+
export type ChannelContexts = Record<string, ChannelContext>;
|
|
23
|
+
export type ArrayOneOrMore<T> = [T, ...T[]];
|
|
24
|
+
export type ParamsType = Record<"label" | "deviceType" | "category" | "product" | "title" | "label" | "name" | "fromValue" | "toValue", string>;
|
|
25
|
+
export type EventDefinition = {
|
|
26
|
+
name: string;
|
|
27
|
+
type: "structured" | "unstructured";
|
|
28
|
+
makePayload: (params?: Record<string, unknown>) => StructuredEvent | SelfDescribingJson<Record<string, unknown>>;
|
|
29
|
+
};
|
|
30
|
+
export interface PageDataProps extends Partial<Record<"scripts", Array<{
|
|
31
|
+
metadata: {
|
|
32
|
+
name: string;
|
|
33
|
+
};
|
|
34
|
+
props?: Record<string, unknown>;
|
|
35
|
+
}>>> {
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./text";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RenderOptions } from "@testing-library/react";
|
|
2
|
+
import { ReactElement } from "react";
|
|
3
|
+
export declare const renderWithProviders: (ui: ReactElement, options?: RenderOptions) => import("@testing-library/react").RenderResult<typeof import("@testing-library/dom/types/queries"), HTMLElement, HTMLElement>;
|
|
4
|
+
export declare const mockLocation: ({ origin, pathname, }: {
|
|
5
|
+
origin?: string;
|
|
6
|
+
pathname?: string;
|
|
7
|
+
}) => Window & typeof globalThis;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const snakeCase: (text?: string) => string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@simplybusiness/services",
|
|
3
|
+
"license": "UNLICENSED",
|
|
4
|
+
"version": "0.1.1",
|
|
5
|
+
"description": "Internal library for services",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+ssh://git@github.com/simplybusiness/mobius.git"
|
|
9
|
+
},
|
|
10
|
+
"simplyBusiness": {
|
|
11
|
+
"publishToPublicNpm": true
|
|
12
|
+
},
|
|
13
|
+
"main": "dist/cjs/index.js",
|
|
14
|
+
"module": "dist/esm/index.js",
|
|
15
|
+
"types": "./dist/types/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"src",
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/types/index.d.ts",
|
|
23
|
+
"require": "./dist/cjs/index.js",
|
|
24
|
+
"import": "./dist/esm/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"clean": "rm -rf dist",
|
|
29
|
+
"build": "yarn run -T turbo run turbo:build",
|
|
30
|
+
"prepack": "yarn run build",
|
|
31
|
+
"build:cjs": "cd src && swc --config-file ../../.swcrc . -d ../dist/cjs -C module.type=commonjs",
|
|
32
|
+
"build:esm": "cd src && swc --config-file ../../.swcrc . -d ../dist/esm -C module.type=es6",
|
|
33
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
34
|
+
"lint": "eslint --ext .tsx,.ts,.js,.jsx,.mjs .",
|
|
35
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
36
|
+
"test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --collect-coverage",
|
|
37
|
+
"check-types": "tsc --noEmit --pretty"
|
|
38
|
+
},
|
|
39
|
+
"sideEffects": false,
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"react": "^18.2.0",
|
|
42
|
+
"react-dom": "^18.2.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@react-types/shared": "^3.23.1",
|
|
46
|
+
"@swc/cli": "^0.3.14",
|
|
47
|
+
"@swc/core": "^1.6.5",
|
|
48
|
+
"@swc/jest": "^0.2.36",
|
|
49
|
+
"@testing-library/dom": "^10.2.0",
|
|
50
|
+
"@testing-library/jest-dom": "6.4.6",
|
|
51
|
+
"@testing-library/react": "^16.0.0",
|
|
52
|
+
"@types/jest": "^29.5.12",
|
|
53
|
+
"@types/react": "^18.3.3",
|
|
54
|
+
"@types/react-dom": "^18.3.0",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
|
56
|
+
"@typescript-eslint/parser": "^7.14.1",
|
|
57
|
+
"eslint": "^8.57.0",
|
|
58
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
59
|
+
"eslint-config-prettier": "^9.1.0",
|
|
60
|
+
"eslint-import-resolver-typescript": "^3.6.1",
|
|
61
|
+
"eslint-plugin-import": "^2.29.1",
|
|
62
|
+
"eslint-plugin-jsx-a11y": "^6.9.0",
|
|
63
|
+
"eslint-plugin-no-only-tests": "^3.1.0",
|
|
64
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
65
|
+
"eslint-plugin-react": "^7.34.3",
|
|
66
|
+
"eslint-plugin-react-hooks": "^4.6.2",
|
|
67
|
+
"identity-obj-proxy": "^3.0.0",
|
|
68
|
+
"jest": "^29.7.0",
|
|
69
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
70
|
+
"prettier": "^3.3.2",
|
|
71
|
+
"react": "^18.3.1",
|
|
72
|
+
"react-dom": "^18.3.1",
|
|
73
|
+
"ts-jest": "^29.1.5",
|
|
74
|
+
"tslib": "^2.6.3",
|
|
75
|
+
"typescript": "^5.5.2"
|
|
76
|
+
},
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"@airbrake/browser": "^2.1.8",
|
|
79
|
+
"@simplybusiness/mobius": "^4.13.0",
|
|
80
|
+
"@snowplow/browser-tracker": "^3.24.0",
|
|
81
|
+
"classnames": "^2.5.1"
|
|
82
|
+
},
|
|
83
|
+
"lint-staged": {
|
|
84
|
+
"*.{js,ts,jsx,tsx}": "eslint --ext .tsx,.ts,.js,.jsx,.mjs --fix"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const pageData = {
|
|
2
|
+
scripts: [
|
|
3
|
+
{
|
|
4
|
+
metadata: { name: "snowplow" },
|
|
5
|
+
props: {
|
|
6
|
+
uid: "49a449d8aaa9dd58f90a623d4b9dbcae235bf92a",
|
|
7
|
+
cookieDomain: "",
|
|
8
|
+
// TODO: Change this url to "http://localhost:8000" for local development
|
|
9
|
+
avalancheCollector:
|
|
10
|
+
"https://snowplow-collector-staging.simplybusiness.com",
|
|
11
|
+
appId: "us-chopin",
|
|
12
|
+
includeGAContext: true,
|
|
13
|
+
eventMethod: "post",
|
|
14
|
+
postPath: "/com.simplybusiness/events",
|
|
15
|
+
trackActivity: true,
|
|
16
|
+
trackPageView: true,
|
|
17
|
+
pageViewContext: {
|
|
18
|
+
schema: "igluuk.co.simplybusiness/journey_context/jsonschema/1-0-0",
|
|
19
|
+
data: {
|
|
20
|
+
site: "simplybusiness_us",
|
|
21
|
+
vertical: "usa",
|
|
22
|
+
super_segment: "Unknown",
|
|
23
|
+
primary_detail: "Lawn care services",
|
|
24
|
+
journey_name: "usa",
|
|
25
|
+
journey_id: "666ff79d90abbc3582e496da",
|
|
26
|
+
page_step_name: "thank_you_ssr",
|
|
27
|
+
page_step_depth: -1,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
distributionChannelContext: {
|
|
31
|
+
schema:
|
|
32
|
+
"iglucom.simplybusiness/distribution_channel_context/jsonschema/1-0-0",
|
|
33
|
+
data: { service_channel_identifier: "simplybusiness_us" },
|
|
34
|
+
},
|
|
35
|
+
serviceChannelContext: {
|
|
36
|
+
schema:
|
|
37
|
+
"iglucom.simplybusiness/service_channel_context/jsonschema/1-0-0",
|
|
38
|
+
data: { service_channel_identifier: "simplybusiness_us" },
|
|
39
|
+
},
|
|
40
|
+
forceSecureTracker: true,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./services";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export default [
|
|
2
|
+
{
|
|
3
|
+
name: "navButtonClicked",
|
|
4
|
+
type: "structured",
|
|
5
|
+
makePayload: (params: { label: "next" | "back" | "redirect" }) => {
|
|
6
|
+
const { label } = params;
|
|
7
|
+
return {
|
|
8
|
+
category: "navigation",
|
|
9
|
+
action: "thankyou_navigation_button_click",
|
|
10
|
+
label,
|
|
11
|
+
property: "test-property",
|
|
12
|
+
};
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "questionAnswered",
|
|
17
|
+
type: "unstructured",
|
|
18
|
+
makePayload: (params: {
|
|
19
|
+
vertical?: string;
|
|
20
|
+
question: string;
|
|
21
|
+
answer?: string;
|
|
22
|
+
}) => {
|
|
23
|
+
const { vertical, question, answer } = params;
|
|
24
|
+
return {
|
|
25
|
+
schema:
|
|
26
|
+
"iglu:com.simplybusiness/form_question_answered/jsonschema/1-0-1",
|
|
27
|
+
data: {
|
|
28
|
+
site: "",
|
|
29
|
+
vertical: vertical || "business",
|
|
30
|
+
page_index: 1,
|
|
31
|
+
page_name: "Coverage diagnosis questionnaire",
|
|
32
|
+
section_name: "Coverage diagnosis questionnaire",
|
|
33
|
+
question,
|
|
34
|
+
answer,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Set Airbrake configuration for embedded-qcp project
|
|
2
|
+
|
|
3
|
+
import { Notifier } from "@airbrake/browser";
|
|
4
|
+
|
|
5
|
+
const getEnvironment = () =>
|
|
6
|
+
process.env.NODE_ENV === "test" ? "test" : "development";
|
|
7
|
+
|
|
8
|
+
// https://simplybusiness.airbrake.io/projects/512949/edit#tab-access
|
|
9
|
+
const projectId = 512949;
|
|
10
|
+
const projectKey = "4e25197d8faea61c10fbb97702200780";
|
|
11
|
+
|
|
12
|
+
export const airbrake = new Notifier({
|
|
13
|
+
projectId: +projectId,
|
|
14
|
+
projectKey,
|
|
15
|
+
environment: getEnvironment(),
|
|
16
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { pageData } from "../../data/scripts-mock";
|
|
3
|
+
import { getSnowplowConfig } from "./getSnowplowConfig";
|
|
4
|
+
import { SnowplowProvider } from "./SnowplowContext";
|
|
5
|
+
import { PageDataProps } from "./types";
|
|
6
|
+
|
|
7
|
+
const pageDataWithoutScripts = {
|
|
8
|
+
...pageData,
|
|
9
|
+
scripts: [],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const snowplowProps = getSnowplowConfig(
|
|
13
|
+
pageDataWithoutScripts as PageDataProps,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
describe("SnowplowProvider", () => {
|
|
17
|
+
describe("given pagaData has empty scripts entry", () => {
|
|
18
|
+
it("should render children without Snowplow instance errors", () => {
|
|
19
|
+
const text = "Example";
|
|
20
|
+
|
|
21
|
+
render(
|
|
22
|
+
<SnowplowProvider scripts={snowplowProps!}>
|
|
23
|
+
<p>{text}</p>
|
|
24
|
+
</SnowplowProvider>,
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const textElement = screen.getByText(text);
|
|
28
|
+
|
|
29
|
+
expect(textElement).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import {
|
|
3
|
+
createContext,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useState,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { Snowplow } from ".";
|
|
11
|
+
import { getContexts } from "./contexts";
|
|
12
|
+
import { eventDefinitions } from "./event-definitions";
|
|
13
|
+
import { EventDefinition, TrackingProps } from "./types";
|
|
14
|
+
|
|
15
|
+
export interface SnowplowContextInterface {
|
|
16
|
+
config: TrackingProps;
|
|
17
|
+
snowplow?: Snowplow;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const SnowplowContext = createContext<SnowplowContextInterface | null>(null);
|
|
21
|
+
|
|
22
|
+
type ProviderProps = {
|
|
23
|
+
scripts: TrackingProps;
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const SnowplowProvider = ({ scripts, children }: ProviderProps) => {
|
|
28
|
+
const [config, _setConfig] = useState<TrackingProps>(scripts);
|
|
29
|
+
const [snowplow, setSnowplow] = useState<Snowplow>(new Snowplow(config));
|
|
30
|
+
|
|
31
|
+
// Attach event handlers and set contexts
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (snowplow && scripts) {
|
|
34
|
+
const contexts = getContexts(config);
|
|
35
|
+
|
|
36
|
+
snowplow
|
|
37
|
+
.setContexts(contexts)
|
|
38
|
+
.addEventHandlers(eventDefinitions as EventDefinition[]);
|
|
39
|
+
// Send page view event
|
|
40
|
+
if (config.trackPageView) snowplow.trackView();
|
|
41
|
+
}
|
|
42
|
+
}, [config, snowplow, scripts]);
|
|
43
|
+
|
|
44
|
+
const value: SnowplowContextInterface = useMemo(
|
|
45
|
+
() => ({
|
|
46
|
+
config,
|
|
47
|
+
snowplow,
|
|
48
|
+
}),
|
|
49
|
+
[config, snowplow],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<SnowplowContext.Provider value={value}>
|
|
54
|
+
{children}
|
|
55
|
+
</SnowplowContext.Provider>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export function useSnowplowContext() {
|
|
60
|
+
const context = useContext(SnowplowContext);
|
|
61
|
+
|
|
62
|
+
if (!context) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"useSnowplowContext must be used inside a `SnowplowProvider`",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return context;
|
|
68
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { pageData } from "../../data/scripts-mock";
|
|
2
|
+
import { getContexts } from "./contexts";
|
|
3
|
+
import { getSnowplowConfig } from "./getSnowplowConfig";
|
|
4
|
+
import { PageDataProps, TrackingProps } from "./types";
|
|
5
|
+
|
|
6
|
+
describe("Snowplow Contexts", () => {
|
|
7
|
+
it("should extract all context records from snowplow props", () => {
|
|
8
|
+
const snowplowProps = getSnowplowConfig(pageData as PageDataProps);
|
|
9
|
+
const contexts = getContexts(snowplowProps as TrackingProps);
|
|
10
|
+
|
|
11
|
+
expect(contexts).toHaveLength(3);
|
|
12
|
+
expect(contexts[0]).toEqual({
|
|
13
|
+
pageViewContext: {
|
|
14
|
+
schema: "igluuk.co.simplybusiness/journey_context/jsonschema/1-0-0",
|
|
15
|
+
data: {
|
|
16
|
+
site: "simplybusiness_us",
|
|
17
|
+
vertical: "usa",
|
|
18
|
+
super_segment: "Unknown",
|
|
19
|
+
primary_detail: "Lawn care services",
|
|
20
|
+
journey_name: "usa",
|
|
21
|
+
journey_id: "666ff79d90abbc3582e496da",
|
|
22
|
+
page_step_name: "thank_you_ssr",
|
|
23
|
+
page_step_depth: -1,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
expect(contexts[1]).toEqual({
|
|
28
|
+
distributionChannelContext: {
|
|
29
|
+
schema:
|
|
30
|
+
"iglucom.simplybusiness/distribution_channel_context/jsonschema/1-0-0",
|
|
31
|
+
data: { service_channel_identifier: "simplybusiness_us" },
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
expect(contexts[2]).toEqual({
|
|
35
|
+
serviceChannelContext: {
|
|
36
|
+
schema:
|
|
37
|
+
"iglucom.simplybusiness/service_channel_context/jsonschema/1-0-0",
|
|
38
|
+
data: { service_channel_identifier: "simplybusiness_us" },
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SelfDescribingJson } from "@snowplow/browser-tracker";
|
|
2
|
+
import { TrackingProps } from "./types";
|
|
3
|
+
|
|
4
|
+
export const getContexts = (
|
|
5
|
+
config: TrackingProps,
|
|
6
|
+
): SelfDescribingJson<Record<string, unknown>>[] => {
|
|
7
|
+
const contexts =
|
|
8
|
+
config &&
|
|
9
|
+
Object.entries(config)
|
|
10
|
+
.filter(([key]) => key.includes("Context") && key !== "includeGAContext")
|
|
11
|
+
.map(([key, value]) => ({ [key]: value }));
|
|
12
|
+
|
|
13
|
+
return contexts as unknown as SelfDescribingJson<Record<string, unknown>>[];
|
|
14
|
+
};
|