@meetelise/chat 1.42.2 → 1.42.4

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/src/MyPubnub.ts CHANGED
@@ -6,9 +6,10 @@ import { LogType, sendLoggingEvent } from "./analytics";
6
6
  import { ChatStorageKey, createChatStorageKey } from "./handleChatId";
7
7
  import LeadSourceClient from "./WebComponent/LeadSourceClient";
8
8
  import { pushGtmEvent } from "./gtm";
9
- import { isContainingEmail } from "./utils";
9
+ import { isContainingEmail, snakify } from "./utils";
10
10
  import { WidgetType } from "./main/MEChat";
11
11
  import { BuildingWebchatView } from "./fetchBuildingWebchatView";
12
+ import { LeadSourceMultitouchClient } from "./WebComponent/LeadSourceMultitouchClient";
12
13
 
13
14
  interface TokenResponse {
14
15
  auth: {
@@ -94,6 +95,8 @@ class MyPubnub {
94
95
  private apiHost = "https://app.meetelise.com";
95
96
 
96
97
  private leadSourceClient: LeadSourceClient | null = null;
98
+ private leadSourceMultitouchClient: LeadSourceMultitouchClient | null = null;
99
+
97
100
  private buildingWebchatView: BuildingWebchatView | null = null;
98
101
  private buildingSlug: string;
99
102
  private orgSlug: string;
@@ -188,6 +191,7 @@ class MyPubnub {
188
191
  orgSlug: string,
189
192
  leadSource: string | null = null,
190
193
  leadUserId: string,
194
+ leadSourceMultitouchClient: LeadSourceMultitouchClient | null,
191
195
  leadSourceClient: LeadSourceClient | null = null,
192
196
  widgetType: WidgetType = WidgetType.Default
193
197
  ) {
@@ -198,6 +202,7 @@ class MyPubnub {
198
202
  this.leadUserId = leadUserId;
199
203
  this.channel = `webchat_${leadUserId}`;
200
204
  this.leadSourceClient = leadSourceClient;
205
+ this.leadSourceMultitouchClient = leadSourceMultitouchClient;
201
206
  this.widgetType = widgetType;
202
207
  }
203
208
 
@@ -608,8 +613,14 @@ class MyPubnub {
608
613
  leadSource: this.leadSource,
609
614
  widgetType: this.widgetType,
610
615
  isDevState: this.shouldCreateAsDevState(),
616
+ lead_sources_with_timestamps: (
617
+ this.leadSourceMultitouchClient?.getSafeLeadSourceTouchpointsWithDefault(
618
+ { includedUserSelectedLeadSource: null }
619
+ ) ?? []
620
+ ).map((source) => snakify({ ...source })),
611
621
  },
612
622
  });
623
+ this.leadSourceMultitouchClient?.resetLeadSourceTouchpoints();
613
624
  }
614
625
 
615
626
  if (!this.isFirstChatMessageSent) {
@@ -145,16 +145,20 @@ export class TableMatrixQtySelector extends LitElement {
145
145
  .join(" ");
146
146
  }
147
147
 
148
- private renderItemType(type: string): TemplateResult {
148
+ private renderItemType(type: string, isSingleItem: boolean): TemplateResult {
149
149
  const quantity = this.quantities[type] ?? 0;
150
150
  const maxQty = this.getMaxQuantityForType(type);
151
151
  const canIncrement =
152
152
  this.isValidCombination(type, quantity + 1) && quantity < maxQty;
153
153
  const formattedType = this.formatItemType(type);
154
154
 
155
+ const showTypeLabel = !isSingleItem;
156
+
155
157
  return html`
156
158
  <div class="item-type-row">
157
- <div class="item-label">${formattedType}:</div>
159
+ ${showTypeLabel
160
+ ? html`<div class="item-label">${formattedType}:</div>`
161
+ : html`<div></div>`}
158
162
  <div class="quantity-control ${this.disabled ? "unavailable" : ""}">
159
163
  <button
160
164
  class="quantity-button"
@@ -188,9 +192,11 @@ export class TableMatrixQtySelector extends LitElement {
188
192
  const types = this.itemTypes;
189
193
  if (!types.length) return html``;
190
194
 
195
+ const isSingleItem = types.length === 1;
196
+
191
197
  return html`
192
198
  <div class="matrix-container">
193
- ${types.map((type) => this.renderItemType(type))}
199
+ ${types.map((type) => this.renderItemType(type, isSingleItem))}
194
200
  </div>
195
201
  `;
196
202
  }
@@ -100,6 +100,6 @@ export class BuildingFeeView {
100
100
  }
101
101
 
102
102
  get hasMatrix(): boolean {
103
- return !!(this.pricingType === "custom" && this.customMatrixData);
103
+ return !!this.customMatrixData;
104
104
  }
105
105
  }
@@ -0,0 +1,222 @@
1
+ import addDays from "date-fns/addDays";
2
+ import formatISO from "date-fns/formatISO";
3
+ import parseISO from "date-fns/parseISO";
4
+ import { getCampaignSources, LogType, sendLoggingEvent } from "../analytics";
5
+ import { getUrlQueryParameters } from "../postLeadSources";
6
+ import { getDefaultLeadSourceAttribution } from "./LeadSourceClient";
7
+
8
+ interface LeadSourceParameters {
9
+ websiteOrigin: string | null;
10
+ websiteSearch: string | null;
11
+ queryParameters: {
12
+ [queryKey: string]: string;
13
+ } | null;
14
+ referrer: string | null;
15
+ parsedUtmSource: string | null;
16
+ campaignSources: string[] | null;
17
+ }
18
+
19
+ export interface LeadSourceSubmittedListItem {
20
+ timestampInitiallyLogged: string;
21
+ leadSourceValue: string | null;
22
+ type: "default" | "touchpoint" | "user-selected";
23
+ }
24
+
25
+ export interface LeadSourceValueWithTimestamp
26
+ extends LeadSourceSubmittedListItem {
27
+ parameters: LeadSourceParameters | null;
28
+ }
29
+
30
+ /*
31
+ Stored in local storage as a json of
32
+ {
33
+ timestampExpires: string,
34
+ leadSources: LeadSourceValueWithTimestamp[]
35
+ }
36
+ */
37
+
38
+ export class LeadSourceMultitouchClient {
39
+ constructor(orgSlug: string, buildingSlug: string) {
40
+ this.orgSlug = orgSlug;
41
+ this.buildingSlug = buildingSlug;
42
+ }
43
+ orgSlug: string;
44
+ buildingSlug: string;
45
+
46
+ private persistLeadSourceTTLDays = 30;
47
+ private maxSourcesNonPropertyWebsiteCount = 3; // 3 based on vibes from the team
48
+
49
+ private _generateLeadSourceLocalStorageKey = (): string => {
50
+ return `com.eliseai.webchat.leadsources.v2.buildingslug=${this.buildingSlug}`;
51
+ };
52
+ private _generateNewExpirationTimestamp = (): string => {
53
+ return formatISO(addDays(new Date(), this.persistLeadSourceTTLDays));
54
+ };
55
+ private _generateLeadSourceParameters = () => {
56
+ const queryParameters = getUrlQueryParameters();
57
+ return {
58
+ websiteOrigin: window.location.origin,
59
+ websiteSearch: window.location.search,
60
+ queryParameters: queryParameters,
61
+ referrer: document.referrer,
62
+ parsedUtmSource: queryParameters ? queryParameters["utm_source"] : null,
63
+ campaignSources: Object.values(getCampaignSources()).filter(
64
+ (source) => source
65
+ ),
66
+ };
67
+ };
68
+
69
+ addSafeLeadSourceTouchpoint = (leadSourceValue: string): void => {
70
+ const leadSourceLocalStorageParsed = this.getLocalStorageMultitouchValue();
71
+ const leadSourceLocalStorageKey = this._generateLeadSourceLocalStorageKey();
72
+ if (
73
+ !leadSourceLocalStorageParsed ||
74
+ this.isExpiredTimestamp(leadSourceLocalStorageParsed.timestampExpires)
75
+ ) {
76
+ const newMultitouchLeadSourceInfo: {
77
+ timestampExpires: string;
78
+ leadSources: LeadSourceValueWithTimestamp[];
79
+ } = {
80
+ timestampExpires: this._generateNewExpirationTimestamp(),
81
+ leadSources: [
82
+ {
83
+ parameters: this._generateLeadSourceParameters(),
84
+ leadSourceValue: leadSourceValue,
85
+ timestampInitiallyLogged: formatISO(new Date()),
86
+ type: "touchpoint",
87
+ },
88
+ ],
89
+ };
90
+ localStorage.setItem(
91
+ leadSourceLocalStorageKey,
92
+ JSON.stringify(newMultitouchLeadSourceInfo)
93
+ );
94
+ } else {
95
+ // check if source already exists
96
+ const existingLeadSource = leadSourceLocalStorageParsed.leadSources.find(
97
+ (source) => source.leadSourceValue === leadSourceValue
98
+ );
99
+ if (existingLeadSource) {
100
+ // if it already exists, we dont need to add again or update timestamp!
101
+ return;
102
+ }
103
+ if (
104
+ leadSourceLocalStorageParsed.leadSources.length <
105
+ this.maxSourcesNonPropertyWebsiteCount
106
+ ) {
107
+ // if we have enough space, can add
108
+ leadSourceLocalStorageParsed.leadSources.push({
109
+ parameters: this._generateLeadSourceParameters(),
110
+ leadSourceValue: leadSourceValue,
111
+ timestampInitiallyLogged: formatISO(new Date()),
112
+ type: "touchpoint",
113
+ });
114
+ leadSourceLocalStorageParsed.timestampExpires =
115
+ this._generateNewExpirationTimestamp();
116
+ localStorage.setItem(
117
+ leadSourceLocalStorageKey,
118
+ JSON.stringify(leadSourceLocalStorageParsed)
119
+ );
120
+ return;
121
+ } else {
122
+ // eslint-disable-next-line no-console
123
+ console.warn(
124
+ `Too many lead sources for ${this.buildingSlug}, max is ${this.maxSourcesNonPropertyWebsiteCount}`
125
+ );
126
+ sendLoggingEvent({
127
+ logType: LogType.warn,
128
+ buildingSlug: this.buildingSlug,
129
+ orgSlug: this.orgSlug,
130
+ logTitle: "TOO_MANY_LEAD_SOURCES",
131
+ logData: {
132
+ buildingSlug: this.buildingSlug,
133
+ },
134
+ });
135
+ }
136
+ }
137
+ };
138
+
139
+ getSafeLeadSourceTouchpointsWithDefault = ({
140
+ includedUserSelectedLeadSource,
141
+ }: {
142
+ includedUserSelectedLeadSource: string | null;
143
+ }): LeadSourceSubmittedListItem[] => {
144
+ const leadSourcesParsed = this.getLocalStorageMultitouchValue();
145
+ const defaultLeadSource = getDefaultLeadSourceAttribution(this.orgSlug);
146
+ if (!leadSourcesParsed) {
147
+ const defaultedList: LeadSourceSubmittedListItem[] = [
148
+ {
149
+ leadSourceValue: defaultLeadSource,
150
+ timestampInitiallyLogged: formatISO(new Date()),
151
+ type: "default",
152
+ },
153
+ ];
154
+ if (includedUserSelectedLeadSource) {
155
+ defaultedList.push({
156
+ leadSourceValue: includedUserSelectedLeadSource,
157
+ timestampInitiallyLogged: formatISO(new Date()),
158
+ type: "user-selected",
159
+ });
160
+ }
161
+ return defaultedList;
162
+ }
163
+ const oldestTimestamp =
164
+ leadSourcesParsed.leadSources.length > 0
165
+ ? leadSourcesParsed.leadSources.sort(
166
+ (a, b) =>
167
+ parseISO(a.timestampInitiallyLogged).getTime() -
168
+ parseISO(b.timestampInitiallyLogged).getTime()
169
+ )[0].timestampInitiallyLogged
170
+ : formatISO(new Date());
171
+
172
+ const parsedList: LeadSourceSubmittedListItem[] = [
173
+ {
174
+ timestampInitiallyLogged: oldestTimestamp,
175
+ leadSourceValue: defaultLeadSource,
176
+ type: "default",
177
+ },
178
+ ...leadSourcesParsed.leadSources.map((source) => ({
179
+ timestampInitiallyLogged: source.timestampInitiallyLogged,
180
+ leadSourceValue: source.leadSourceValue,
181
+ type: source.type,
182
+ })),
183
+ ];
184
+ if (includedUserSelectedLeadSource) {
185
+ parsedList.push({
186
+ leadSourceValue: includedUserSelectedLeadSource,
187
+ timestampInitiallyLogged: formatISO(new Date()),
188
+ type: "user-selected",
189
+ });
190
+ }
191
+ return parsedList;
192
+ };
193
+
194
+ private getLocalStorageMultitouchValue = (): {
195
+ timestampExpires: string;
196
+ leadSources: LeadSourceValueWithTimestamp[];
197
+ } | null => {
198
+ const leadSourceKey = this._generateLeadSourceLocalStorageKey();
199
+ const leadSourceRawValue = localStorage.getItem(leadSourceKey);
200
+
201
+ if (!leadSourceRawValue) {
202
+ return null;
203
+ }
204
+ const leadSourcesParsed: {
205
+ timestampExpires: string;
206
+ leadSources: LeadSourceValueWithTimestamp[];
207
+ } = JSON.parse(leadSourceRawValue);
208
+ return leadSourcesParsed;
209
+ };
210
+
211
+ private isExpiredTimestamp = (timestamp: string) => {
212
+ const timestampExpires = parseISO(timestamp);
213
+ const now = new Date();
214
+ return timestampExpires < now;
215
+ };
216
+
217
+ resetLeadSourceTouchpoints = (): boolean => {
218
+ const leadSourceKey = this._generateLeadSourceLocalStorageKey();
219
+ localStorage.removeItem(leadSourceKey);
220
+ return true;
221
+ };
222
+ }
@@ -28,7 +28,7 @@ import { DatePicker } from "./date-picker";
28
28
  import { MESelect } from "../me-select";
29
29
  import { TimePicker } from "./time-picker";
30
30
  import { LabeledOption } from "../../fetchBuildingInfo";
31
- import { isMobile, isValidPhoneNumber } from "../../utils";
31
+ import { isMobile, isValidPhoneNumber, snakify } from "../../utils";
32
32
  import axios, { AxiosError } from "axios";
33
33
  import mapValues from "lodash/mapValues";
34
34
  import classnames from "classnames";
@@ -54,6 +54,7 @@ import formatInTimeZone from "date-fns-tz/formatInTimeZone";
54
54
  import { getTimezoneAbbreviation } from "../../getTimezoneString";
55
55
  import startOfDay from "date-fns/startOfDay";
56
56
  import isSameDay from "date-fns/isSameDay";
57
+ import { LeadSourceMultitouchClient } from "../LeadSourceMultitouchClient";
57
58
 
58
59
  @customElement("tour-scheduler")
59
60
  export class TourScheduler extends LitElement {
@@ -87,6 +88,9 @@ export class TourScheduler extends LitElement {
87
88
  @property({ attribute: true })
88
89
  private leadSourceClient: LeadSourceClient | null = null;
89
90
 
91
+ @property({ attribute: true })
92
+ private leadSourceMultitouchClient: LeadSourceMultitouchClient | null = null;
93
+
90
94
  @property({ attribute: true })
91
95
  buildingName = "";
92
96
 
@@ -649,6 +653,17 @@ export class TourScheduler extends LitElement {
649
653
  ],
650
654
  query_params: Object.fromEntries(queryParams.entries()),
651
655
  conversation_tracking_id: this.leadSourceClient?.chatId,
656
+ lead_sources_with_timestamps: (
657
+ this.leadSourceMultitouchClient?.getSafeLeadSourceTouchpointsWithDefault(
658
+ {
659
+ includedUserSelectedLeadSource:
660
+ this.selectedLeadSource?.value &&
661
+ this.selectedLeadSource.value.length > 0
662
+ ? this.selectedLeadSource.value
663
+ : null,
664
+ }
665
+ ) ?? []
666
+ ).map((source) => snakify({ ...source })),
652
667
  };
653
668
 
654
669
  const url = `https://app.meetelise.com/platformApi/state/create/v2/scheduleMe`;
@@ -666,6 +681,7 @@ export class TourScheduler extends LitElement {
666
681
  webchatAction: "tour-scheduler",
667
682
  stateId: null,
668
683
  });
684
+ this.leadSourceMultitouchClient?.resetLeadSourceTouchpoints();
669
685
  this.isSubmitting = false;
670
686
  this.tourIsBooked = true;
671
687
  } catch (e: unknown) {
@@ -4,11 +4,15 @@ import { customElement, property, state } from "lit/decorators.js";
4
4
  import { classMap } from "lit/directives/class-map.js";
5
5
  import { createRef, ref, Ref } from "lit/directives/ref.js";
6
6
  import { pushGtmEvent } from "../../gtm";
7
- import { isMobile } from "../../utils";
7
+ import { isMobile, snakify } from "../../utils";
8
8
  import { PhoneOutlineIcon } from "../icons/PhoneOutlineIcon";
9
9
  import LeadSourceClient, {
10
10
  getDefaultLeadSourceAttribution,
11
11
  } from "../LeadSourceClient";
12
+ import {
13
+ LeadSourceMultitouchClient,
14
+ LeadSourceSubmittedListItem,
15
+ } from "../LeadSourceMultitouchClient";
12
16
 
13
17
  import { getOfficeHourText } from "../OfficeHours";
14
18
  import {
@@ -166,6 +170,9 @@ export class CallUsWindow extends LitElement {
166
170
  @property({ attribute: true })
167
171
  private leadSourceClient: LeadSourceClient | null = null;
168
172
 
173
+ @property({ attribute: true })
174
+ private leadSourceMultitouchClient: LeadSourceMultitouchClient | null = null;
175
+
169
176
  phoneNumberInputRef: Ref<HTMLInputElement> = createRef();
170
177
 
171
178
  @state()
@@ -235,12 +242,18 @@ export class CallUsWindow extends LitElement {
235
242
  : [getDefaultLeadSourceAttribution(this.orgSlug)]
236
243
  ),
237
244
  ],
238
- this.leadSourceClient?.chatId
245
+ this.leadSourceClient?.chatId,
246
+ this.leadSourceMultitouchClient?.getSafeLeadSourceTouchpointsWithDefault(
247
+ {
248
+ includedUserSelectedLeadSource: null,
249
+ }
250
+ )
239
251
  );
240
252
  this.leadSourceClient?.checkAndHandleForLogLeadSource({
241
253
  webchatAction: "text-us",
242
254
  stateId: null,
243
255
  });
256
+ this.leadSourceMultitouchClient?.resetLeadSourceTouchpoints();
244
257
  this.hasSubmittedForm = true;
245
258
  this.submittingTextUsOption = false;
246
259
  } catch (e) {
@@ -428,7 +441,8 @@ const createTextWithUs = async (
428
441
  orgSlug: string,
429
442
  buildingSlug: string,
430
443
  leadSources: string[],
431
- chatId?: string | null
444
+ chatId?: string | null,
445
+ leadSourcesWithTimestamps?: LeadSourceSubmittedListItem[]
432
446
  ) => {
433
447
  const formattedPhoneNumber =
434
448
  "+1" +
@@ -447,6 +461,9 @@ const createTextWithUs = async (
447
461
  // @ts-ignore
448
462
  query_params: Object.fromEntries(queryParams.entries()),
449
463
  conversation_tracking_id: chatId,
464
+ lead_sources_with_timestamps: (leadSourcesWithTimestamps ?? []).map(
465
+ (source) => snakify({ ...source })
466
+ ),
450
467
  };
451
468
  pushGtmEvent("textUsSubmitted", {
452
469
  phone: formattedPhoneNumber,
@@ -16,10 +16,14 @@ import axios from "axios";
16
16
  import { FeatureFlagsShowDropdown } from "../../fetchFeatureFlag";
17
17
  import { pushGtmEvent } from "../../gtm";
18
18
  import formDisclaimer from "../../disclaimers";
19
- import { isMobile } from "../../utils";
19
+ import { isMobile, snakify } from "../../utils";
20
20
  import LeadSourceClient, {
21
21
  getDefaultLeadSourceAttribution,
22
22
  } from "../LeadSourceClient";
23
+ import {
24
+ LeadSourceMultitouchClient,
25
+ LeadSourceSubmittedListItem,
26
+ } from "../LeadSourceMultitouchClient";
23
27
 
24
28
  @customElement("email-us-window")
25
29
  export class EmailUsWindow extends LitElement {
@@ -120,6 +124,9 @@ export class EmailUsWindow extends LitElement {
120
124
  @property({ attribute: true })
121
125
  private leadSourceClient: LeadSourceClient | null = null;
122
126
 
127
+ @property({ attribute: true })
128
+ private leadSourceMultitouchClient: LeadSourceMultitouchClient | null = null;
129
+
123
130
  @property({ attribute: true })
124
131
  featureFlagShowDropdown = "";
125
132
 
@@ -275,12 +282,22 @@ export class EmailUsWindow extends LitElement {
275
282
  : [getDefaultLeadSourceAttribution(this.orgSlug)]
276
283
  ),
277
284
  ],
278
- this.leadSourceClient?.chatId
285
+ this.leadSourceClient?.chatId,
286
+ this.leadSourceMultitouchClient?.getSafeLeadSourceTouchpointsWithDefault(
287
+ {
288
+ includedUserSelectedLeadSource:
289
+ this.selectedLeadSource?.value &&
290
+ this.selectedLeadSource.value.length > 0
291
+ ? this.selectedLeadSource.value
292
+ : null,
293
+ }
294
+ )
279
295
  );
280
296
  this.leadSourceClient?.checkAndHandleForLogLeadSource({
281
297
  webchatAction: "email-us",
282
298
  stateId: null,
283
299
  });
300
+ this.leadSourceMultitouchClient?.resetLeadSourceTouchpoints();
284
301
  this.hasSubmittedForm = true;
285
302
  this.isSubmitting = false;
286
303
  // Remove the height of the button when it leaves the loading state
@@ -509,7 +526,8 @@ const createEmail = async (
509
526
  orgSlug: string,
510
527
  buildingSlug: string,
511
528
  leadSources: string[],
512
- chatId?: string | null
529
+ chatId?: string | null,
530
+ leadSourcesWithTimestamps?: LeadSourceSubmittedListItem[]
513
531
  ) => {
514
532
  const formattedPhoneNumber =
515
533
  "+1" +
@@ -532,6 +550,9 @@ const createEmail = async (
532
550
  // @ts-ignore
533
551
  query_params: Object.fromEntries(queryParams.entries()),
534
552
  conversation_tracking_id: chatId,
553
+ lead_sources_with_timestamps: (leadSourcesWithTimestamps ?? []).map(
554
+ (source) => snakify({ ...source })
555
+ ),
535
556
  };
536
557
  pushGtmEvent("emailUsSubmitted", {
537
558
  firstName,
@@ -151,6 +151,7 @@ export class HealthChat extends LitElement {
151
151
  this.currentLeadSource,
152
152
  updatedChatStorageKey.leadId,
153
153
  null,
154
+ null,
154
155
  WidgetType.Healthcare
155
156
  );
156
157
 
@@ -45,6 +45,7 @@ import {
45
45
  getRawAvailabilities,
46
46
  resetAvailabilitiesCache,
47
47
  } from "../../getAvailabilities";
48
+ import { LeadSourceMultitouchClient } from "../LeadSourceMultitouchClient";
48
49
 
49
50
  @customElement("meetelise-launcher")
50
51
  export class Launcher extends LitElement {
@@ -202,6 +203,9 @@ export class Launcher extends LitElement {
202
203
  @property({ attribute: true })
203
204
  private leadSourceClient: LeadSourceClient | null = null;
204
205
 
206
+ @state()
207
+ private leadSourceMultitouchClient: LeadSourceMultitouchClient | null = null;
208
+
205
209
  @state()
206
210
  isEmailWindowOpen = false;
207
211
  @state()
@@ -1184,6 +1188,7 @@ export class Launcher extends LitElement {
1184
1188
  .buildingId=${this.buildingId}
1185
1189
  .buildingName=${this.buildingName}
1186
1190
  .leadSourceClient=${this.leadSourceClient}
1191
+ .leadSourceMultitouchClient=${this.leadSourceMultitouchClient}
1187
1192
  .orgLegalName=${this.orgLegalName}
1188
1193
  >
1189
1194
  </email-us-window>
@@ -1223,6 +1228,7 @@ export class Launcher extends LitElement {
1223
1228
  ? this.showTourNextToChat
1224
1229
  : ""}
1225
1230
  .leadSourceClient=${this.leadSourceClient}
1231
+ .leadSourceMultitouchClient=${this.leadSourceMultitouchClient}
1226
1232
  ${ref(this.tourSchedulerRef)}
1227
1233
  ></tour-scheduler>
1228
1234
  </div>`
@@ -1252,6 +1258,7 @@ export class Launcher extends LitElement {
1252
1258
  buildingName="${this.buildingName}"
1253
1259
  orgSlug="${this.orgSlug}"
1254
1260
  .leadSourceClient=${this.leadSourceClient}
1261
+ .leadSourceMultitouchClient=${this.leadSourceMultitouchClient}
1255
1262
  .orgLegalName=${this.orgLegalName}
1256
1263
  ></call-us-window>
1257
1264
  </div>
@@ -65,6 +65,7 @@ import { WidgetType } from "../main/MEChat";
65
65
  import { replaceSelectButtonsWithNewLink } from "../replaceSelectButtonsWithNewLink";
66
66
 
67
67
  import "./chat-additional-actions";
68
+ import { LeadSourceMultitouchClient } from "./LeadSourceMultitouchClient";
68
69
 
69
70
  @customElement("me-chat")
70
71
  export class MEChat extends LitElement {
@@ -179,7 +180,10 @@ export class MEChat extends LitElement {
179
180
  private myPubnub: MyPubnub | null = null;
180
181
 
181
182
  @state()
182
- private LeadSourceClient: LeadSourceClient | null = null;
183
+ private LeadSourceClient: LeadSourceClient | null = null; // DEPRECATED IN FAVOR OF LeadSourceMultitouchClient
184
+
185
+ @state()
186
+ private LeadSourceMultitouchClient: LeadSourceMultitouchClient | null = null;
183
187
 
184
188
  @state()
185
189
  private sampleRateToUse = 0.05;
@@ -547,21 +551,35 @@ export class MEChat extends LitElement {
547
551
  throw new Error("Lead ID is null");
548
552
  }
549
553
  this.LeadSourceClient = new LeadSourceClient();
554
+
555
+ this.LeadSourceMultitouchClient = new LeadSourceMultitouchClient(
556
+ this.orgSlug,
557
+ this.buildingSlug
558
+ );
559
+
550
560
  this.myPubnub = new MyPubnub(
551
561
  this.buildingSlug,
552
562
  this.buildingWebchatView,
553
563
  this.orgSlug,
554
564
  null, // initialize lead source as null initially
555
565
  updatedChatStorageKey.leadId,
566
+ this.LeadSourceMultitouchClient,
556
567
  this.LeadSourceClient,
557
568
  this.widgetType
558
569
  );
559
570
  this.LeadSourceClient.chatId = this.myPubnub.channel;
560
- await this.LeadSourceClient?.generateUserLeadSource({
561
- leadId: this.myPubnub?.leadUserId ?? "",
562
- orgSlug: this.orgSlug,
563
- buildingSlug: this.buildingSlug,
564
- });
571
+ const generatedLeadSource =
572
+ await this.LeadSourceClient?.generateUserLeadSource({
573
+ leadId: this.myPubnub?.leadUserId ?? "",
574
+ orgSlug: this.orgSlug,
575
+ buildingSlug: this.buildingSlug,
576
+ });
577
+
578
+ if (generatedLeadSource) {
579
+ this.LeadSourceMultitouchClient.addSafeLeadSourceTouchpoint(
580
+ generatedLeadSource
581
+ );
582
+ }
565
583
 
566
584
  // eslint-disable-next-line no-console
567
585
  console.log(
@@ -961,6 +979,7 @@ export class MEChat extends LitElement {
961
979
  .left=${this.left}
962
980
  .right=${this.right}
963
981
  .leadSourceClient=${this.LeadSourceClient}
982
+ .leadSourceMultitouchClient=${this.LeadSourceMultitouchClient}
964
983
  >
965
984
  </meetelise-launcher>`
966
985
  : ""
@@ -150,6 +150,7 @@ export class UtilitiesChat extends LitElement {
150
150
  this.currentLeadSource,
151
151
  updatedChatStorageKey.leadId,
152
152
  null,
153
+ null,
153
154
  WidgetType.Utilities
154
155
  );
155
156