@meetelise/chat 1.48.3 → 1.48.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.
@@ -32,9 +32,13 @@ class LeadSourceClient {
32
32
 
33
33
  private apiHost = "https://app.meetelise.com";
34
34
  public leadSource: string | null = null;
35
+ // UTM params associated with the resolved lead source (e.g. switch_code=<code>
36
+ // for AMLI). Forwarded onto external tour-vendor links (e.g. Tour24).
37
+ public leadSourceParams: { [key: string]: string } | null = null;
35
38
  private localStorageTTLDays = 30;
36
39
 
37
40
  buildingId: number | null = null;
41
+ orgId: number | null = null;
38
42
  orgSlug: string | null = null;
39
43
  buildingSlug: string | null = null;
40
44
  queryParameters: {
@@ -90,6 +94,7 @@ class LeadSourceClient {
90
94
 
91
95
  const body = {
92
96
  leadSource: leadSource,
97
+ leadSourceParams: this.leadSourceParams,
93
98
  leadId: leadId,
94
99
  buildingSlug: buildingSlug,
95
100
  timestamp: formatISO(new Date()),
@@ -140,17 +145,33 @@ class LeadSourceClient {
140
145
  referrer,
141
146
  campaignSources,
142
147
  }: LeadSourceInput): Promise<string | null> {
148
+ const requestBody = {
149
+ query_params: queryParams,
150
+ building_slug: buildingSlug,
151
+ referrer: referrer,
152
+ campaign_sources: campaignSources,
153
+ };
143
154
  try {
144
- const currentParsedLeadSourceResponse = await axios.post(
145
- `${this.apiHost}/platformApi/webchat/current-parsed-lead-source`,
146
- {
147
- query_params: queryParams,
148
- building_slug: buildingSlug,
149
- referrer: referrer,
150
- campaign_sources: campaignSources,
151
- }
155
+ // Only AMLI (org 52) needs the resolved source's params forwarded to its
156
+ // self-guided tour vendor (Tour24); every other org uses the original
157
+ // endpoint that returns just the source string.
158
+ if (this.orgId !== 52) {
159
+ const response = await axios.post(
160
+ `${this.apiHost}/platformApi/webchat/current-parsed-lead-source`,
161
+ requestBody
162
+ );
163
+ return response.data;
164
+ }
165
+ const response = await axios.post(
166
+ `${this.apiHost}/platformApi/webchat/current-parsed-lead-source-with-params`,
167
+ requestBody
152
168
  );
153
- return currentParsedLeadSourceResponse.data;
169
+ const data = response.data as {
170
+ source: string | null;
171
+ utm_params: { [key: string]: string } | null;
172
+ };
173
+ this.leadSourceParams = data?.utm_params ?? null;
174
+ return data?.source ?? null;
154
175
  } catch (_) {
155
176
  return null;
156
177
  }
@@ -291,10 +312,14 @@ class LeadSourceClient {
291
312
  isOverrideFromNewLeadSource = true;
292
313
  } else {
293
314
  this.leadSource = isCurrentlyStoredLeadSource.leadSource;
315
+ this.leadSourceParams =
316
+ isCurrentlyStoredLeadSource.leadSourceParams ?? null;
294
317
  return this.leadSource;
295
318
  }
296
319
  } else {
297
320
  this.leadSource = isCurrentlyStoredLeadSource.leadSource;
321
+ this.leadSourceParams =
322
+ isCurrentlyStoredLeadSource.leadSourceParams ?? null;
298
323
  return this.leadSource;
299
324
  }
300
325
  }
@@ -314,6 +339,8 @@ class LeadSourceClient {
314
339
  this.getLeadSourceBodyIfValid(buildingSlug);
315
340
  if (isCurrentlyStoredLeadSource) {
316
341
  this.leadSource = isCurrentlyStoredLeadSource.leadSource;
342
+ this.leadSourceParams =
343
+ isCurrentlyStoredLeadSource.leadSourceParams ?? null;
317
344
  return this.leadSource;
318
345
  }
319
346
  }
@@ -44,6 +44,7 @@ import compareAsc from "date-fns/compareAsc";
44
44
  import { InputStyles } from "../actions/InputStyles";
45
45
  import { classMap } from "lit/directives/class-map.js";
46
46
  import { FeatureFlagsShowDropdown } from "../../fetchFeatureFlag";
47
+ import { appendParamsToUrl } from "../../postLeadSources";
47
48
  import { pushGtmEvent } from "../../gtm";
48
49
  import formDisclaimer from "../../disclaimers";
49
50
  import { tourSchedulerStyles } from "./tourSchedulerStyles";
@@ -85,6 +86,18 @@ export class TourScheduler extends LitElement {
85
86
  }
86
87
  }
87
88
 
89
+ // Open the configured self-guided tour (e.g. Tour24) link. For org 52 (AMLI)
90
+ // we forward the resolved lead source's params (e.g. switch_code=<code>) onto
91
+ // the link so the vendor can attribute the lead; every other org opens the
92
+ // link unchanged.
93
+ private openSelfGuidedTour(): void {
94
+ const url =
95
+ this.orgId === 52
96
+ ? appendParamsToUrl(this.sgtUrl, this.leadSourceParams)
97
+ : this.sgtUrl;
98
+ window.open(url, "_blank");
99
+ }
100
+
88
101
  @property({ attribute: false })
89
102
  tourTypeOptions: LabeledOption[] = [];
90
103
  @property({ attribute: false })
@@ -93,6 +106,10 @@ export class TourScheduler extends LitElement {
93
106
  chatId = "";
94
107
  @property({ type: Number })
95
108
  buildingId = 0;
109
+ @property({ type: Number })
110
+ orgId = 0;
111
+ @property({ attribute: false })
112
+ leadSourceParams: { [key: string]: string } | null = null;
96
113
  @property({ attribute: true })
97
114
  buildingSlug = "";
98
115
  @property({ attribute: true })
@@ -987,7 +1004,7 @@ export class TourScheduler extends LitElement {
987
1004
  this.selfGuidedToursTypeOffered
988
1005
  )
989
1006
  ) {
990
- window.open(this.sgtUrl, "_blank");
1007
+ this.openSelfGuidedTour();
991
1008
  }
992
1009
  this.availabilitiesGroupedByDay =
993
1010
  await getAvailabilitiesGroupedByDay(
@@ -1118,7 +1135,7 @@ export class TourScheduler extends LitElement {
1118
1135
  <div id="dateAndTimeMenu">
1119
1136
  <button
1120
1137
  id="self-guided-redirect-bttn"
1121
- @click=${() => window.open(this.sgtUrl, "_blank")}
1138
+ @click=${() => this.openSelfGuidedTour()}
1122
1139
  >
1123
1140
  View Self Guided Tour Times
1124
1141
  </button>
@@ -1144,7 +1161,7 @@ export class TourScheduler extends LitElement {
1144
1161
  this.selfGuidedToursTypeOffered
1145
1162
  )
1146
1163
  ) {
1147
- window.open(this.sgtUrl, "_blank");
1164
+ this.openSelfGuidedTour();
1148
1165
  return;
1149
1166
  }
1150
1167
  if (
@@ -80,6 +80,10 @@ export class Launcher extends LitElement {
80
80
  chatCallUsHeader = "";
81
81
  @property({ attribute: false })
82
82
  buildingId = 0;
83
+ @property({ type: Number })
84
+ orgId = 0;
85
+ @property({ attribute: false })
86
+ leadSourceParams: { [key: string]: string } | null = null;
83
87
  @property({ attribute: true })
84
88
  buildingSlug = "";
85
89
  @property({ attribute: true })
@@ -1305,6 +1309,8 @@ export class Launcher extends LitElement {
1305
1309
  .layoutOptions=${this.layoutOptions}
1306
1310
  .orgLegalName=${this.orgLegalName}
1307
1311
  buildingId=${this.buildingId}
1312
+ orgId=${this.orgId}
1313
+ .leadSourceParams=${this.leadSourceParams}
1308
1314
  featureFlagShowDropdown="${this.featureFlagShowDropdown}"
1309
1315
  .buildingName=${this.buildingName}
1310
1316
  .primaryColor=${this.primaryColor}
@@ -589,6 +589,7 @@ export class MEChat extends LitElement {
589
589
  throw new Error("Lead ID is null");
590
590
  }
591
591
  this.LeadSourceClient = new LeadSourceClient();
592
+ this.LeadSourceClient.orgId = this.buildingWebchatView?.orgId ?? 0;
592
593
 
593
594
  this.LeadSourceMultitouchClient = new LeadSourceMultitouchClient(
594
595
  this.orgSlug,
@@ -1002,6 +1003,9 @@ export class MEChat extends LitElement {
1002
1003
  ${ref(this.launcherRef)}
1003
1004
  .isFirstMount=${!this.hasMounted}
1004
1005
  .buildingId=${this.buildingWebchatView?.id ?? 0}
1006
+ .orgId=${this.buildingWebchatView?.orgId ?? 0}
1007
+ .leadSourceParams=${this.LeadSourceClient?.leadSourceParams ??
1008
+ null}
1005
1009
  .hasDynamicSchedulingEnabled=${this.buildingWebchatView
1006
1010
  ?.usesDynamicScheduling ?? false}
1007
1011
  .orgLegalName=${this.buildingWebchatView?.orgLegalName ?? ""}
@@ -5,6 +5,31 @@ export function getUrlQueryParameters(): { [queryKey: string]: string } | null {
5
5
  return getStandardUrlQueryParameters();
6
6
  }
7
7
 
8
+ // Append the given query params onto an outbound tour-vendor URL (e.g. Tour24)
9
+ // so the vendor can attribute the lead. The params are the ones associated with
10
+ // the resolved lead source (returned by the backend, e.g. switch_code=<code>
11
+ // for AMLI) and are forwarded exactly as configured. Existing params on the vendor URL
12
+ // are preserved unless overridden. Fails safe (returns the URL unchanged) on a
13
+ // malformed URL.
14
+ export function appendParamsToUrl(
15
+ baseUrl: string,
16
+ params: { [key: string]: string } | null
17
+ ): string {
18
+ if (!baseUrl || !params) {
19
+ return baseUrl;
20
+ }
21
+ try {
22
+ const url = new URL(baseUrl);
23
+ Object.entries(params).forEach(([key, value]) => {
24
+ url.searchParams.set(key, value);
25
+ });
26
+ return url.toString();
27
+ } catch (_) {
28
+ // Malformed sgtUrl - fail safe and open it unmodified
29
+ return baseUrl;
30
+ }
31
+ }
32
+
8
33
  function getStandardUrlQueryParameters(): {
9
34
  [queryKey: string]: string;
10
35
  } | null {