@meetelise/chat 1.58.0 → 1.59.0
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/dist/src/trackingParams.d.ts +1 -0
- package/package.json +1 -1
- package/public/dist/index.js +583 -588
- package/src/MyPubnub.ts +2 -0
- package/src/WebComponent/Scheduler/tour-scheduler.ts +2 -0
- package/src/WebComponent/actions/call-us-window.ts +2 -0
- package/src/WebComponent/actions/email-us-window.ts +2 -0
- package/src/WebComponent/leasing-chat-styles.ts +1 -2
- package/src/WebComponent/me-chat.ts +2 -0
- package/src/WebComponent/pubnub-chat.ts +14 -16
- package/src/assistantName.test.ts +152 -0
- package/src/trackingParams.test.ts +32 -0
- package/src/trackingParams.ts +42 -0
package/src/MyPubnub.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getTrackingParams } from "./trackingParams";
|
|
1
2
|
import { AxiosError } from "axios";
|
|
2
3
|
import Pubnub, { ListenerParameters, MessageEvent } from "pubnub";
|
|
3
4
|
|
|
@@ -792,6 +793,7 @@ class MyPubnub {
|
|
|
792
793
|
buildingSlug: this.buildingSlug,
|
|
793
794
|
userId: this.buildingWebchatView?.userId, // this userid is actually the AI user!
|
|
794
795
|
leadSource: this.leadSource,
|
|
796
|
+
trackingParams: getTrackingParams(this.orgSlug),
|
|
795
797
|
widgetType: this.widgetType,
|
|
796
798
|
isDevState: shouldCreateAsDevState(location.href),
|
|
797
799
|
// Read by the backend only for orgs in the org-level webchat rollout.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import { getTrackingParams } from "../../trackingParams";
|
|
2
3
|
import { html, LitElement, PropertyValueMap, TemplateResult } from "lit";
|
|
3
4
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
4
5
|
import "../actions/international-phone-input";
|
|
@@ -872,6 +873,7 @@ export class TourScheduler extends LitElement {
|
|
|
872
873
|
email_address: this.email,
|
|
873
874
|
phone_number: phoneNumber,
|
|
874
875
|
building_id: this.buildingId,
|
|
876
|
+
tracking_params: getTrackingParams(this.orgSlug),
|
|
875
877
|
first_name: this.firstNameInput?.value ?? this.firstNameInputValue,
|
|
876
878
|
last_name: this.lastNameInput?.value ?? this.lastNameInputValue,
|
|
877
879
|
tour_type: tourTypeForSubmission[this.tourType],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getTrackingParams } from "../../trackingParams";
|
|
1
2
|
import axios from "axios";
|
|
2
3
|
import { css, html, LitElement, TemplateResult } from "lit";
|
|
3
4
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -512,6 +513,7 @@ const createTextWithUs = async (
|
|
|
512
513
|
// @ts-ignore
|
|
513
514
|
query_params: Object.fromEntries(queryParams.entries()),
|
|
514
515
|
conversation_tracking_id: chatId,
|
|
516
|
+
tracking_params: getTrackingParams(orgSlug),
|
|
515
517
|
lead_sources_with_timestamps: (leadSourcesWithTimestamps ?? []).map(
|
|
516
518
|
(source) => snakify({ ...source })
|
|
517
519
|
),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getTrackingParams } from "../../trackingParams";
|
|
1
2
|
import { css, html, LitElement, TemplateResult } from "lit";
|
|
2
3
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
3
4
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
@@ -865,6 +866,7 @@ const createEmail = async (
|
|
|
865
866
|
// @ts-ignore
|
|
866
867
|
query_params: Object.fromEntries(queryParams.entries()),
|
|
867
868
|
conversation_tracking_id: chatId,
|
|
869
|
+
tracking_params: getTrackingParams(orgSlug),
|
|
868
870
|
lead_sources_with_timestamps: (leadSourcesWithTimestamps ?? []).map(
|
|
869
871
|
(source) => snakify({ ...source })
|
|
870
872
|
),
|
|
@@ -47,8 +47,7 @@ export const leasingChatStyles = css`
|
|
|
47
47
|
justify-content: space-between;
|
|
48
48
|
}
|
|
49
49
|
.leasing-conversation-body-backdrop {
|
|
50
|
-
background:
|
|
51
|
-
backdrop-filter: blur(4px);
|
|
50
|
+
background: #efefef;
|
|
52
51
|
|
|
53
52
|
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
|
54
53
|
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getTrackingParams } from "../trackingParams";
|
|
1
2
|
import { css, html, LitElement, TemplateResult } from "lit";
|
|
2
3
|
import { customElement, property, state } from "lit/decorators.js";
|
|
3
4
|
import { classMap } from "lit/directives/class-map.js";
|
|
@@ -1519,6 +1520,7 @@ const overrideContactUsForm = async (
|
|
|
1519
1520
|
first_message: formValues.message,
|
|
1520
1521
|
building_id: buildingWebchatView.id,
|
|
1521
1522
|
is_external_form: true,
|
|
1523
|
+
tracking_params: getTrackingParams(orgSlug),
|
|
1522
1524
|
lead_sources: [
|
|
1523
1525
|
...new Set(
|
|
1524
1526
|
leadSource
|
|
@@ -253,6 +253,8 @@ export class PubnubChat extends LitElement {
|
|
|
253
253
|
return html``; // error should be here
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
const assistantName = this.building?.userFirstName || "Elise";
|
|
257
|
+
|
|
256
258
|
const buildingId = this.building?.id;
|
|
257
259
|
let styles = {};
|
|
258
260
|
if (this._isMobile) {
|
|
@@ -357,9 +359,8 @@ export class PubnubChat extends LitElement {
|
|
|
357
359
|
</li>
|
|
358
360
|
<li
|
|
359
361
|
class="message-container ai-message"
|
|
360
|
-
tabindex="0"
|
|
361
362
|
role="article"
|
|
362
|
-
aria-label="
|
|
363
|
+
aria-label="${assistantName}: Hi I'm ${assistantName}. How can I assist you today?"
|
|
363
364
|
>
|
|
364
365
|
<p
|
|
365
366
|
class=${classMap({
|
|
@@ -368,7 +369,7 @@ export class PubnubChat extends LitElement {
|
|
|
368
369
|
["webchat-font__mobile"]: this._isMobile,
|
|
369
370
|
})}
|
|
370
371
|
>
|
|
371
|
-
Hi I'm
|
|
372
|
+
Hi I'm ${assistantName}. How can I assist you today?
|
|
372
373
|
</p>
|
|
373
374
|
</li>
|
|
374
375
|
${this.messages.map((message) => {
|
|
@@ -378,11 +379,10 @@ export class PubnubChat extends LitElement {
|
|
|
378
379
|
? "message-container lead-message"
|
|
379
380
|
: "message-container ai-message"}
|
|
380
381
|
key=${message.timestamp}
|
|
381
|
-
tabindex="0"
|
|
382
382
|
role="article"
|
|
383
383
|
aria-label="${message.isLeadMessage
|
|
384
384
|
? "You"
|
|
385
|
-
:
|
|
385
|
+
: assistantName}: ${messageAriaLabel(message)}"
|
|
386
386
|
>
|
|
387
387
|
${isSimpleNavigationChatMessage(message)
|
|
388
388
|
? html`<pubnub-navigation
|
|
@@ -436,6 +436,7 @@ export class PubnubChat extends LitElement {
|
|
|
436
436
|
<div id="utilities-inner-footer">
|
|
437
437
|
<textarea
|
|
438
438
|
id="message-input"
|
|
439
|
+
aria-label="Message"
|
|
439
440
|
class=${classMap({
|
|
440
441
|
["webchat-font__desktop"]: !this._isMobile,
|
|
441
442
|
["webchat-font__mobile"]: this._isMobile,
|
|
@@ -535,9 +536,8 @@ export class PubnubChat extends LitElement {
|
|
|
535
536
|
</li>
|
|
536
537
|
<li
|
|
537
538
|
class="message-container ai-message"
|
|
538
|
-
tabindex="0"
|
|
539
539
|
role="article"
|
|
540
|
-
aria-label="
|
|
540
|
+
aria-label="${assistantName}: Hi I'm ${assistantName}. If this is a medical emergency, please call 911. How can I assist you today?"
|
|
541
541
|
>
|
|
542
542
|
<p
|
|
543
543
|
class=${classMap({
|
|
@@ -546,8 +546,8 @@ export class PubnubChat extends LitElement {
|
|
|
546
546
|
["webchat-font__mobile"]: this._isMobile,
|
|
547
547
|
})}
|
|
548
548
|
>
|
|
549
|
-
Hi I'm
|
|
550
|
-
How can I assist you today?
|
|
549
|
+
Hi I'm ${assistantName}. If this is a medical emergency,
|
|
550
|
+
please call 911. How can I assist you today?
|
|
551
551
|
</p>
|
|
552
552
|
</li>
|
|
553
553
|
${this.messages.map((message) => {
|
|
@@ -557,11 +557,10 @@ export class PubnubChat extends LitElement {
|
|
|
557
557
|
? "message-container lead-message"
|
|
558
558
|
: "message-container ai-message"}
|
|
559
559
|
key=${message.timestamp}
|
|
560
|
-
tabindex="0"
|
|
561
560
|
role="article"
|
|
562
561
|
aria-label="${message.isLeadMessage
|
|
563
562
|
? "You"
|
|
564
|
-
:
|
|
563
|
+
: assistantName}: ${messageAriaLabel(message)}"
|
|
565
564
|
>
|
|
566
565
|
${isSimpleNavigationChatMessage(message)
|
|
567
566
|
? html`<pubnub-navigation
|
|
@@ -615,6 +614,7 @@ export class PubnubChat extends LitElement {
|
|
|
615
614
|
<div id="healthcare-inner-footer">
|
|
616
615
|
<textarea
|
|
617
616
|
id="message-input"
|
|
617
|
+
aria-label="Message"
|
|
618
618
|
class=${classMap({
|
|
619
619
|
["webchat-font__desktop"]: !this._isMobile,
|
|
620
620
|
["webchat-font__mobile"]: this._isMobile,
|
|
@@ -734,9 +734,8 @@ export class PubnubChat extends LitElement {
|
|
|
734
734
|
"ai-message": true,
|
|
735
735
|
"with-box-shadow": orgId === 444,
|
|
736
736
|
})}
|
|
737
|
-
tabindex="0"
|
|
738
737
|
role="article"
|
|
739
|
-
aria-label="
|
|
738
|
+
aria-label="${assistantName}: ${this.building.welcomeMessage}"
|
|
740
739
|
>
|
|
741
740
|
<p
|
|
742
741
|
class=${classMap({
|
|
@@ -760,11 +759,10 @@ export class PubnubChat extends LitElement {
|
|
|
760
759
|
"with-box-shadow": orgId === 444,
|
|
761
760
|
})}
|
|
762
761
|
key=${message.timestamp}
|
|
763
|
-
tabindex="0"
|
|
764
762
|
role="article"
|
|
765
763
|
aria-label="${message.isLeadMessage
|
|
766
764
|
? "You"
|
|
767
|
-
:
|
|
765
|
+
: assistantName}: ${messageAriaLabel(message)}"
|
|
768
766
|
>
|
|
769
767
|
${isSimpleNavigationChatMessage(message)
|
|
770
768
|
? html`<pubnub-navigation
|
|
@@ -822,6 +820,7 @@ export class PubnubChat extends LitElement {
|
|
|
822
820
|
>
|
|
823
821
|
<textarea
|
|
824
822
|
id="message-input"
|
|
823
|
+
aria-label="Message"
|
|
825
824
|
class=${classMap({
|
|
826
825
|
["webchat-font__desktop"]: !this._isMobile,
|
|
827
826
|
["webchat-font__mobile"]: this._isMobile,
|
|
@@ -855,7 +854,6 @@ export class PubnubChat extends LitElement {
|
|
|
855
854
|
@click=${() => this.sendMessage(this.messageInput.value)}
|
|
856
855
|
?disabled=${this.myPubnub?.isCurrentlyStreamingMessage}
|
|
857
856
|
aria-label="Send message"
|
|
858
|
-
aria-describedby="Send message"
|
|
859
857
|
>
|
|
860
858
|
${shouldUsePrimaryColorForChatFooter(
|
|
861
859
|
this.building.orgId,
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import "../public/dist/index";
|
|
3
|
+
import { BuildingWebchatView } from "./fetchBuildingWebchatView";
|
|
4
|
+
import type { SimpleChatMessage } from "./MyPubnub";
|
|
5
|
+
import type { PubnubChat } from "./WebComponent/pubnub-chat";
|
|
6
|
+
|
|
7
|
+
type WidgetTypeName = "default" | "healthcare" | "utilities";
|
|
8
|
+
|
|
9
|
+
declare const afterEach: (callback: () => void) => void;
|
|
10
|
+
declare const it: (name: string, callback: () => void | Promise<void>) => void;
|
|
11
|
+
|
|
12
|
+
const text = (visible: string): string => visible.replace(/\s+/g, " ").trim();
|
|
13
|
+
|
|
14
|
+
const conversation = (): SimpleChatMessage[] => [
|
|
15
|
+
{
|
|
16
|
+
timestamp: 1,
|
|
17
|
+
message: "Do you have a two bedroom?",
|
|
18
|
+
isLeadMessage: true,
|
|
19
|
+
chunks: [{ text: "Do you have a two bedroom?", order: 0, isDone: true }],
|
|
20
|
+
type: "text",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
timestamp: 2,
|
|
24
|
+
message: "Yes, I can help with that.",
|
|
25
|
+
isLeadMessage: false,
|
|
26
|
+
chunks: [{ text: "Yes, I can help with that.", order: 0, isDone: true }],
|
|
27
|
+
type: "text",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
timestamp: 3,
|
|
31
|
+
media: [{ title: null, description: null, url: null }],
|
|
32
|
+
isLeadMessage: false,
|
|
33
|
+
type: "media",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
timestamp: 4,
|
|
37
|
+
navigation: {
|
|
38
|
+
url: "https://example.com/floor-plans",
|
|
39
|
+
label: "the floor plans",
|
|
40
|
+
},
|
|
41
|
+
isLeadMessage: false,
|
|
42
|
+
type: "navigation",
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const mount = async (
|
|
47
|
+
widgetType: WidgetTypeName,
|
|
48
|
+
assistantName: string | null
|
|
49
|
+
): Promise<PubnubChat> => {
|
|
50
|
+
const chat = document.createElement("pubnub-chat") as PubnubChat;
|
|
51
|
+
chat.buildingSlug = "alta-federal-hill";
|
|
52
|
+
chat.orgSlug = "greystar";
|
|
53
|
+
chat.widgetType = widgetType;
|
|
54
|
+
if (assistantName !== null) {
|
|
55
|
+
chat.building = {
|
|
56
|
+
id: 1,
|
|
57
|
+
orgId: 1,
|
|
58
|
+
name: "Alta Federal Hill",
|
|
59
|
+
userFirstName: assistantName,
|
|
60
|
+
welcomeMessage: `Hi, I'm ${assistantName}. How can I help you today?`,
|
|
61
|
+
state: "MD",
|
|
62
|
+
country: "US",
|
|
63
|
+
customAdditionalDisclaimer: null,
|
|
64
|
+
} as BuildingWebchatView;
|
|
65
|
+
}
|
|
66
|
+
document.body.appendChild(chat);
|
|
67
|
+
await chat.updateComplete;
|
|
68
|
+
// firstUpdated clears messages until PubNub has history.
|
|
69
|
+
chat.messages = conversation();
|
|
70
|
+
await chat.updateComplete;
|
|
71
|
+
return chat;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const labels = (chat: PubnubChat): string[] =>
|
|
75
|
+
Array.from(
|
|
76
|
+
chat.shadowRoot?.querySelectorAll<HTMLElement>('[role="article"]') ?? []
|
|
77
|
+
).map((article) => article.getAttribute("aria-label") ?? "");
|
|
78
|
+
|
|
79
|
+
afterEach(() => {
|
|
80
|
+
document.querySelectorAll("pubnub-chat").forEach((chat) => chat.remove());
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("announces leasing messages as the configured assistant", async () => {
|
|
84
|
+
const chat = await mount("default", "Emily");
|
|
85
|
+
const articles = Array.from(
|
|
86
|
+
chat.shadowRoot?.querySelectorAll<HTMLElement>('[role="article"]') ?? []
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
expect(text(articles[0].innerText)).to.equal(
|
|
90
|
+
"Hi, I'm Emily. How can I help you today?"
|
|
91
|
+
);
|
|
92
|
+
expect(labels(chat)).to.deep.equal([
|
|
93
|
+
"Emily: Hi, I'm Emily. How can I help you today?",
|
|
94
|
+
"You: Do you have a two bedroom?",
|
|
95
|
+
"Emily: Yes, I can help with that.",
|
|
96
|
+
"Emily: Media message",
|
|
97
|
+
"Emily: Take me to the floor plans",
|
|
98
|
+
]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("announces healthcare messages as the configured assistant", async () => {
|
|
102
|
+
const chat = await mount("healthcare", "Ezra");
|
|
103
|
+
const greeting = chat.shadowRoot?.querySelector<HTMLElement>(
|
|
104
|
+
"#message-thread-list > li.message-container"
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
expect(text(greeting?.innerText ?? "")).to.equal(
|
|
108
|
+
"Hi I'm Ezra. If this is a medical emergency, please call 911. How can I assist you today?"
|
|
109
|
+
);
|
|
110
|
+
expect(labels(chat)[0]).to.equal(
|
|
111
|
+
"Ezra: Hi I'm Ezra. If this is a medical emergency, please call 911. How can I assist you today?"
|
|
112
|
+
);
|
|
113
|
+
expect(labels(chat).slice(1)).to.deep.equal([
|
|
114
|
+
"You: Do you have a two bedroom?",
|
|
115
|
+
"Ezra: Yes, I can help with that.",
|
|
116
|
+
"Ezra: Media message",
|
|
117
|
+
"Ezra: Take me to the floor plans",
|
|
118
|
+
]);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("announces utilities messages as the configured assistant", async () => {
|
|
122
|
+
const chat = await mount("utilities", "Emily");
|
|
123
|
+
const greeting = chat.shadowRoot?.querySelector<HTMLElement>(
|
|
124
|
+
"#message-thread-list > li.message-container"
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
expect(text(greeting?.innerText ?? "")).to.equal(
|
|
128
|
+
"Hi I'm Emily. How can I assist you today?"
|
|
129
|
+
);
|
|
130
|
+
expect(labels(chat)).to.deep.equal([
|
|
131
|
+
"Emily: Hi I'm Emily. How can I assist you today?",
|
|
132
|
+
"You: Do you have a two bedroom?",
|
|
133
|
+
"Emily: Yes, I can help with that.",
|
|
134
|
+
"Emily: Media message",
|
|
135
|
+
"Emily: Take me to the floor plans",
|
|
136
|
+
]);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("keeps Elise when a chat has no configured assistant name", async () => {
|
|
140
|
+
const chat = await mount("utilities", null);
|
|
141
|
+
const greeting = chat.shadowRoot?.querySelector<HTMLElement>(
|
|
142
|
+
"#message-thread-list > li.message-container"
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
expect(text(greeting?.innerText ?? "")).to.equal(
|
|
146
|
+
"Hi I'm Elise. How can I assist you today?"
|
|
147
|
+
);
|
|
148
|
+
expect(labels(chat)[0]).to.equal(
|
|
149
|
+
"Elise: Hi I'm Elise. How can I assist you today?"
|
|
150
|
+
);
|
|
151
|
+
expect(labels(chat)[2]).to.equal("Elise: Yes, I can help with that.");
|
|
152
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import { getTrackingParams } from "./trackingParams";
|
|
3
|
+
|
|
4
|
+
const originalUrl = window.location.href;
|
|
5
|
+
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
localStorage.removeItem("xdtid");
|
|
8
|
+
window.history.replaceState(null, "", originalUrl);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("reads Greystar's xdtid from localStorage", () => {
|
|
12
|
+
localStorage.setItem("xdtid", "from-storage");
|
|
13
|
+
window.history.replaceState(null, "", "?xdtid=from-url");
|
|
14
|
+
|
|
15
|
+
expect(getTrackingParams("greystar")).to.deep.equal({
|
|
16
|
+
xdtid: "from-storage",
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("falls back to the xdtid URL param", () => {
|
|
21
|
+
window.history.replaceState(null, "", "?xdtid=from-url");
|
|
22
|
+
|
|
23
|
+
expect(getTrackingParams("greystar")).to.deep.equal({ xdtid: "from-url" });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("returns null when nothing is found or the org has no config", () => {
|
|
27
|
+
expect(getTrackingParams("greystar")).to.equal(null);
|
|
28
|
+
|
|
29
|
+
localStorage.setItem("xdtid", "from-storage");
|
|
30
|
+
expect(getTrackingParams("avb")).to.equal(null);
|
|
31
|
+
expect(getTrackingParams(null)).to.equal(null);
|
|
32
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
interface TrackingParamSource {
|
|
2
|
+
key: string;
|
|
3
|
+
localStorageKey?: string;
|
|
4
|
+
queryParam?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Client-specific values sent with each new lead and passed to the client's PMS. Add a client here.
|
|
8
|
+
const TRACKING_PARAMS_BY_ORG_SLUG: Record<string, TrackingParamSource[]> = {
|
|
9
|
+
// Greystar's cross-domain tracking id, set by their GTM; localStorage outlives the landing URL.
|
|
10
|
+
greystar: [{ key: "xdtid", localStorageKey: "xdtid", queryParam: "xdtid" }],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const readLocalStorage = (key: string): string | null => {
|
|
14
|
+
try {
|
|
15
|
+
return localStorage.getItem(key);
|
|
16
|
+
} catch (_) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const readQueryParam = (key: string): string | null => {
|
|
22
|
+
try {
|
|
23
|
+
return new URLSearchParams(window.location.search).get(key);
|
|
24
|
+
} catch (_) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const getTrackingParams = (
|
|
30
|
+
orgSlug: string | null | undefined
|
|
31
|
+
): Record<string, string> | null => {
|
|
32
|
+
const sources = orgSlug ? TRACKING_PARAMS_BY_ORG_SLUG[orgSlug] : undefined;
|
|
33
|
+
if (!sources) return null;
|
|
34
|
+
const params: Record<string, string> = {};
|
|
35
|
+
for (const source of sources) {
|
|
36
|
+
const value =
|
|
37
|
+
(source.localStorageKey && readLocalStorage(source.localStorageKey)) ||
|
|
38
|
+
(source.queryParam && readQueryParam(source.queryParam));
|
|
39
|
+
if (value) params[source.key] = value;
|
|
40
|
+
}
|
|
41
|
+
return Object.keys(params).length ? params : null;
|
|
42
|
+
};
|