@meetelise/chat 1.21.0 → 1.21.2

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.
Files changed (76) hide show
  1. package/.github/pull_request_template.md +61 -0
  2. package/.idea/codeStyles/Project.xml +57 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  5. package/.idea/vcs.xml +6 -0
  6. package/.idea/workspace.xml +67 -0
  7. package/README.md +29 -14
  8. package/declarations.d.ts +12 -0
  9. package/package.json +5 -1
  10. package/public/demo/index.html +62 -4
  11. package/public/demo/secret.html +63 -0
  12. package/public/dist/index.js +3184 -1105
  13. package/public/dist/index.js.LICENSE.txt +19 -9
  14. package/public/index.html +6 -4
  15. package/src/MEChat.ts +207 -52
  16. package/src/MyPubnub.ts +657 -0
  17. package/src/WebComponent/LeadSourceClient.ts +300 -0
  18. package/src/WebComponent/Scheduler/date-picker.ts +1 -1
  19. package/src/WebComponent/Scheduler/time-picker.ts +86 -76
  20. package/src/WebComponent/Scheduler/tour-scheduler.ts +694 -764
  21. package/src/WebComponent/Scheduler/tour-type-option.ts +17 -3
  22. package/src/WebComponent/Scheduler/tourSchedulerStyles.ts +418 -0
  23. package/src/WebComponent/actions/InputStyles.ts +32 -10
  24. package/src/WebComponent/actions/action-confirm-button.ts +16 -11
  25. package/src/WebComponent/actions/call-us-window.ts +341 -58
  26. package/src/WebComponent/actions/details-window.ts +30 -16
  27. package/src/WebComponent/actions/email-us-window.ts +89 -58
  28. package/src/WebComponent/actions/formatPhoneNumber.ts +15 -1
  29. package/src/WebComponent/actions/minimize-expand-button.ts +92 -0
  30. package/src/WebComponent/health-chat.ts +267 -0
  31. package/src/WebComponent/healthcare/healthcare-launcher-styles.ts +34 -0
  32. package/src/WebComponent/healthcare/healthcare-launcher.ts +100 -0
  33. package/src/WebComponent/healthchat-styles.ts +119 -0
  34. package/src/WebComponent/index.ts +1 -1
  35. package/src/WebComponent/launcher/Launcher.ts +919 -0
  36. package/src/WebComponent/{launcherStyles.ts → launcher/launcherStyles.ts} +172 -29
  37. package/src/WebComponent/launcher/mobile-launcher.ts +127 -0
  38. package/src/WebComponent/launcher/typeEmojiStyles.ts +161 -0
  39. package/src/WebComponent/launcher/typeMiniStyles.ts +60 -0
  40. package/src/WebComponent/launcher/typeMobileStyles.ts +50 -0
  41. package/src/WebComponent/leasing-chat-styles.ts +114 -0
  42. package/src/WebComponent/me-chat.ts +964 -351
  43. package/src/WebComponent/me-select.ts +48 -21
  44. package/src/WebComponent/mini-loader.ts +28 -0
  45. package/src/WebComponent/pubnub-chat-styles.ts +192 -0
  46. package/src/WebComponent/pubnub-chat.ts +707 -0
  47. package/src/WebComponent/pubnub-media.ts +208 -0
  48. package/src/WebComponent/pubnub-message-styles.ts +54 -0
  49. package/src/WebComponent/pubnub-message.ts +421 -0
  50. package/src/analytics.ts +114 -14
  51. package/src/assetUrls.ts +2 -0
  52. package/src/disclaimers.ts +56 -0
  53. package/src/fetchBuildingABTestType.ts +4 -0
  54. package/src/fetchBuildingInfo.ts +25 -17
  55. package/src/fetchFeatureFlag.ts +147 -0
  56. package/src/fetchLeadSources.ts +67 -1
  57. package/src/fetchPhoneNumberFromSource.ts +31 -0
  58. package/src/fetchWebchatPreferences.ts +55 -0
  59. package/src/getAvailabilities.ts +7 -3
  60. package/src/getBuildingPhoneNumber.ts +26 -0
  61. package/src/getShouldAllowScheduling.ts +16 -0
  62. package/src/getTimezoneString.ts +39 -0
  63. package/src/gtm.ts +17 -0
  64. package/src/handleChatId.ts +101 -0
  65. package/src/insertDNIIntoWebsite.ts +136 -0
  66. package/src/insertLeadSourceIntoSchedulerLinks.ts +50 -0
  67. package/src/postLeadSources.ts +39 -35
  68. package/src/svgIcons.ts +62 -53
  69. package/src/themes.ts +47 -121
  70. package/src/utils.ts +88 -1
  71. package/src/WebComponent/Launcher.ts +0 -559
  72. package/src/WebComponent/actions/text-us-window.ts +0 -279
  73. package/src/chatID.ts +0 -64
  74. package/src/createConversation.ts +0 -57
  75. package/src/fetchCurrentParsedLeadSource.ts +0 -24
  76. package/src/getRegisteredPhoneNumbers.ts +0 -56
@@ -10,6 +10,25 @@ object-assign
10
10
  http://jedwatson.github.io/classnames
11
11
  */
12
12
 
13
+ /*! *****************************************************************************
14
+ Copyright (c) Microsoft Corporation.
15
+
16
+ Permission to use, copy, modify, and/or distribute this software for any
17
+ purpose with or without fee is hereby granted.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
20
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
21
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
22
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
24
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25
+ PERFORMANCE OF THIS SOFTWARE.
26
+ ***************************************************************************** */
27
+
28
+ /*! @license DOMPurify 3.1.2 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.2/LICENSE */
29
+
30
+ /*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */
31
+
13
32
  /**
14
33
  * @license
15
34
  * Copyright 2017 Google LLC
@@ -40,15 +59,6 @@ object-assign
40
59
  * SPDX-License-Identifier: BSD-3-Clause
41
60
  */
42
61
 
43
- /**
44
- * @license
45
- * Lodash <https://lodash.com/>
46
- * Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
47
- * Released under MIT license <https://lodash.com/license>
48
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
49
- * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
50
- */
51
-
52
62
  /** @license React v17.0.2
53
63
  * react.production.min.js
54
64
  *
package/public/index.html CHANGED
@@ -2,7 +2,10 @@
2
2
  <html lang="en-GB">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
5
+ <meta
6
+ name="viewport"
7
+ content="width=device-width, initial-scale=1 user-scalable=1"
8
+ />
6
9
  <title>Chat Dev Page</title>
7
10
  <style>
8
11
  body {
@@ -85,9 +88,8 @@
85
88
  import { debounce } from "https://cdn.skypack.dev/lodash";
86
89
  import "./dist/index.js";
87
90
  const chat = MEChat.start({
88
- organization: "greystar",
89
- building: "e7677f10-a645-11ed-9432-53d3fdbf30f6",
90
- mini: false,
91
+ organization: "test-company",
92
+ building: "e2e-test-yardi-building",
91
93
  });
92
94
  //////////////////////////////////////////////////////////////////
93
95
  // The above code is all a client would need. //
package/src/MEChat.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  import axios from "axios";
2
2
  import { StyleInfo } from "lit/directives/style-map";
3
- import { ThemeIdString } from "./themes";
4
3
  import "./WebComponent/me-chat";
5
4
  import { MEChat as MEChatLitElement } from "./WebComponent/me-chat";
5
+ import "./WebComponent/health-chat";
6
+ import { HealthChat as HealthChatLitElement } from "./WebComponent/health-chat";
7
+
8
+ import { tintColor } from "./themes";
9
+ import { LogType, sendLoggingEvent } from "./analytics";
6
10
 
7
11
  /**
8
12
  * The interface to MeetElise chat.
@@ -16,41 +20,128 @@ import { MEChat as MEChatLitElement } from "./WebComponent/me-chat";
16
20
  * building: 'twin-rivers-pointe'
17
21
  * });
18
22
  */
23
+
24
+ interface PositioningOptions {
25
+ right?: number;
26
+ bottom?: number;
27
+ top?: number;
28
+ left?: number;
29
+ }
30
+
31
+ export interface HealthcareOptions extends PositioningOptions {
32
+ id: string;
33
+ }
19
34
  export default class MEChat {
20
35
  static meChat: MEChatLitElement | null = null;
36
+ static healthChat: HealthChatLitElement | null = null;
21
37
  static orgSlug = "";
22
38
  static mutationObserver: MutationObserver | null = null;
23
39
  static previousUrl = "";
40
+ static hasBuildingSlug: boolean | null = null;
41
+ static brandColor = "";
42
+ static backgroundColor = "";
43
+ static healthcareId = "";
44
+ static overridePlacement: {
45
+ right?: number;
46
+ bottom?: number;
47
+ top?: number;
48
+ left?: number;
49
+ } = {};
24
50
 
25
- static start(opts: Options): void {
26
- // If our clients are Yardi and have a resident portal with rentcafe,
27
- // we do NOT want to display the launcher (if following in shows up anywhere in url)
51
+ static healthcareStart(opts: HealthcareOptions, isInitialStart = true): void {
52
+ if (isInitialStart) {
53
+ this.healthcareId = opts.id;
54
+ this.overridePlacement = {
55
+ right: opts.right,
56
+ bottom: opts.bottom,
57
+ top: opts.top,
58
+ left: opts.left,
59
+ };
60
+ }
61
+ installFont();
62
+ const healthChat = document.createElement("health-chat");
63
+ healthChat.setAttribute("class", "health-chat");
64
+ healthChat.setAttribute("role", "dialog");
65
+ healthChat.setAttribute("aria-label", "EliseAI Healthcare Widget");
66
+ healthChat.setAttribute("aria-describedby", "aria-describe-info");
67
+ healthChat.setAttribute("aria-modal", "true");
68
+ healthChat.setAttribute("healthcareId", opts.id);
69
+
70
+ healthChat.setAttribute("right", opts.right?.toString() || "unset");
71
+ healthChat.setAttribute("bottom", opts.bottom?.toString() || "unset");
72
+ healthChat.setAttribute("top", opts.top?.toString() || "unset");
73
+ healthChat.setAttribute("left", opts.left?.toString() || "unset");
74
+
75
+ document.body.appendChild(healthChat);
76
+ MEChat.healthChat = healthChat;
77
+ }
78
+
79
+ static start(opts: Options, isInitialStart = true): void {
80
+ // If clients are Yardi and have a resident portal with rentcafe,
81
+ // we do NOT want to display the launcher (if following in shows up anywhere in url).
28
82
  if (
29
83
  window.location.pathname.includes("residentservices") ||
30
84
  window.location.pathname.includes("onlineleasing")
31
85
  ) {
32
86
  return;
33
87
  }
34
-
88
+ if (isInitialStart) {
89
+ this.orgSlug =
90
+ opts.organization === "Pacific Urban Residential"
91
+ ? "Pacific-Urban-Residential"
92
+ : opts.organization;
93
+ this.hasBuildingSlug = !!opts.building;
94
+ this.overridePlacement = {
95
+ right: opts?.position?.right,
96
+ bottom: opts?.position?.bottom,
97
+ top: opts?.position?.top,
98
+ left: opts?.position?.left,
99
+ };
100
+ }
35
101
  installFont();
36
- installTalkjsMobileStyleFix();
37
- this.orgSlug = opts.organization;
38
102
  const meChat = document.createElement("me-chat");
39
- meChat.setAttribute("orgSlug", opts.organization);
103
+ meChat.setAttribute(
104
+ "orgSlug",
105
+ opts.organization === "Pacific Urban Residential"
106
+ ? "Pacific-Urban-Residential"
107
+ : opts.organization
108
+ );
40
109
  this.handleBuildingslug(meChat, opts.building);
41
110
  meChat.setAttribute("class", "meetelise-chat");
42
- if (opts.themeId) {
43
- meChat.setAttribute("themeId", opts.themeId);
111
+ meChat.setAttribute("role", "dialog");
112
+ meChat.setAttribute("aria-label", "EliseAI Widget");
113
+ meChat.setAttribute("aria-describedby", "aria-describe-info");
114
+ meChat.setAttribute("aria-modal", "true");
115
+ if (opts.launcherStyles) {
116
+ meChat.launcherStyles = opts.launcherStyles;
44
117
  }
45
- if (opts.avatarSrc) {
46
- meChat.setAttribute("avatarSrc", opts.avatarSrc);
118
+ if (opts.mobileStyles) {
119
+ meChat.mobileStyles = opts.mobileStyles;
47
120
  }
48
- if (opts.mini !== undefined) {
49
- meChat.useMiniWidget = opts.mini;
121
+ if (opts.brandColor) {
122
+ this.brandColor = opts.brandColor;
123
+ // we must tint the brand color, to ensure it is visible
124
+ meChat.setAttribute("brandColor", tintColor(opts.brandColor, 0.3));
50
125
  }
51
- if (opts.launcherStyles) {
52
- meChat.launcherStyles = opts.launcherStyles;
126
+
127
+ if (opts.backgroundColor) {
128
+ this.backgroundColor = opts.backgroundColor;
53
129
  }
130
+
131
+ if (opts.onWidgetLoaded) {
132
+ meChat.onWidgetLoaded = opts.onWidgetLoaded;
133
+ }
134
+ if (opts.position) {
135
+ meChat.setAttribute("right", opts.position.right?.toString() || "unset");
136
+ meChat.setAttribute(
137
+ "bottom",
138
+ opts.position.bottom?.toString() || "unset"
139
+ );
140
+ meChat.setAttribute("top", opts.position.top?.toString() || "unset");
141
+ meChat.setAttribute("left", opts.position.left?.toString() || "unset");
142
+ }
143
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
144
+ (window as any).eliseAi = {};
54
145
  document.body.appendChild(meChat);
55
146
  MEChat.meChat = meChat;
56
147
  }
@@ -71,42 +162,32 @@ export default class MEChat {
71
162
  MEChat.meChat = null;
72
163
  }
73
164
 
74
- static async handleSingleFamilyUrl(): Promise<void> {
75
- this.remove();
76
- const url = window.location.href;
77
- const requestUrl = `https://app.meetelise.com/eliseCrmApi/webchat/microsite_slug?uri=${encodeURIComponent(
78
- url
79
- )}`;
80
- const buildingSlug = await axios.get<string | null>(requestUrl, {
81
- headers: { ["org-slug"]: this.orgSlug },
82
- });
83
- if (!buildingSlug || !buildingSlug.data) {
84
- return;
85
- }
86
- const opts = {
87
- organization: this.orgSlug,
88
- building: buildingSlug.data,
89
- };
90
- this.start(opts);
91
- }
92
-
93
165
  static async handleBuildingslug(
94
166
  meChat: MEChatLitElement,
95
167
  buildingSlug?: string
96
168
  ): Promise<void> {
97
169
  if (buildingSlug) {
98
170
  meChat.setAttribute("buildingSlug", buildingSlug);
171
+ // TODO(JMB): Uncomment this when we want to start logging mismatches instead of just the "no match found" case
172
+ // this.calculateBuildingSlugForLogging(buildingSlug);
173
+ return;
99
174
  }
100
175
 
101
176
  if (this.mutationObserver) {
102
177
  return;
103
178
  }
104
179
 
180
+ this.handleSingleFamilyUrl();
181
+ this.previousUrl = window.location.href;
182
+
105
183
  document.body.addEventListener(
106
184
  "click",
107
185
  () => {
108
186
  requestAnimationFrame(() => {
109
- if (this.previousUrl === window.location.href) {
187
+ if (
188
+ this.previousUrl === window.location.href ||
189
+ this.hasBuildingSlug
190
+ ) {
110
191
  return;
111
192
  }
112
193
  this.previousUrl = window.location.href;
@@ -116,15 +197,103 @@ export default class MEChat {
116
197
  true
117
198
  );
118
199
  }
200
+
201
+ static async handleSingleFamilyUrl(): Promise<void> {
202
+ if (this.hasBuildingSlug) {
203
+ return;
204
+ }
205
+ this.remove();
206
+ const url = window.location.href;
207
+ const requestUrl = `https://app.meetelise.com/platformApi/webchat/microsite_slug?uri=${encodeURIComponent(
208
+ url
209
+ )}`;
210
+ const buildingSlug = await axios.get<string | null>(requestUrl, {
211
+ headers: { ["org-slug"]: this.orgSlug },
212
+ });
213
+ // TODO: Figure out whether we only want to sample a percentage of these
214
+ if (Math.random() < 0.2) {
215
+ sendLoggingEvent({
216
+ logType:
217
+ buildingSlug && buildingSlug.data ? LogType.info : LogType.warn,
218
+ logTitle: `[BUILDING_SLUG_CALCULATED_${
219
+ buildingSlug ? "SUCCESS" : "FAILURE"
220
+ }]`,
221
+ logData: {
222
+ calculatedBuildingSlug: buildingSlug.data,
223
+ url,
224
+ orgSlug: this.orgSlug,
225
+ givenBuildingSlug: null,
226
+ reason: buildingSlug && buildingSlug.data ? null : "No match found",
227
+ },
228
+ });
229
+ }
230
+ if (!buildingSlug || !buildingSlug.data) {
231
+ return;
232
+ }
233
+ const opts = {
234
+ organization: this.orgSlug,
235
+ building: buildingSlug.data,
236
+ brandColor: this.brandColor,
237
+ backgroundColor: this.backgroundColor,
238
+ };
239
+ this.start(opts, false);
240
+ }
241
+
242
+ static async calculateBuildingSlugForLogging(
243
+ givenBuildingSlug: string
244
+ ): Promise<void> {
245
+ // TODO: Figure out whether we only want to sample a percentage of these
246
+ const url = window.location.href;
247
+ const requestUrl = `https://app.meetelise.com/platformApi/webchat/microsite_slug?uri=${encodeURIComponent(
248
+ url
249
+ )}`;
250
+ const buildingSlug = await axios.get<string | null>(requestUrl, {
251
+ headers: { ["org-slug"]: this.orgSlug },
252
+ });
253
+ if (Math.random() < 0.2) {
254
+ sendLoggingEvent({
255
+ logType:
256
+ buildingSlug && buildingSlug.data === givenBuildingSlug
257
+ ? LogType.info
258
+ : LogType.warn,
259
+ logTitle: `[BUILDING_SLUG_CALCULATED_${
260
+ buildingSlug && buildingSlug.data === givenBuildingSlug
261
+ ? "SUCCESS"
262
+ : "FAILURE"
263
+ }]`,
264
+ logData: {
265
+ calculatedBuildingSlug: buildingSlug.data,
266
+ url,
267
+ orgSlug: this.orgSlug,
268
+ givenBuildingSlug,
269
+ reason:
270
+ buildingSlug && buildingSlug.data === givenBuildingSlug
271
+ ? null
272
+ : buildingSlug && !buildingSlug.data
273
+ ? "No match found"
274
+ : buildingSlug && buildingSlug.data !== givenBuildingSlug
275
+ ? "Mismatch"
276
+ : "No match found",
277
+ },
278
+ });
279
+ }
280
+ if (!buildingSlug || !buildingSlug.data) {
281
+ return;
282
+ }
283
+ }
119
284
  }
120
285
 
121
286
  export interface Options {
122
- building?: string;
287
+ building: string;
123
288
  organization: string;
124
- themeId?: ThemeIdString;
125
289
  avatarSrc?: string;
126
290
  mini?: boolean;
127
291
  launcherStyles?: StyleInfo;
292
+ brandColor?: string;
293
+ backgroundColor?: string;
294
+ mobileStyles?: StyleInfo;
295
+ position?: PositioningOptions;
296
+ onWidgetLoaded?: () => void;
128
297
  }
129
298
 
130
299
  /** You can't install a font from CSS in a shadow DOM, so we use JS to do it here in the regular DOM. */
@@ -132,19 +301,5 @@ const installFont = () => {
132
301
  const link = document.createElement("link");
133
302
  link.setAttribute("rel", "stylesheet");
134
303
  link.setAttribute("type", "text/css");
135
- link.setAttribute(
136
- "href",
137
- "https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap"
138
- );
139
304
  document.head.appendChild(link);
140
305
  };
141
-
142
- const installTalkjsMobileStyleFix = () => {
143
- const metaTag = document.createElement("meta");
144
- metaTag.setAttribute("name", "viewport");
145
- metaTag.setAttribute(
146
- "content",
147
- "width=device-width, initial-scale=1, maximum-scale=2"
148
- );
149
- document.head.appendChild(metaTag);
150
- };