@meetelise/chat 1.29.0 → 1.30.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.
Files changed (228) hide show
  1. package/dist/src/MyPubnub.d.ts +116 -0
  2. package/dist/src/WebComponent/FeeCalculator/components/addon-item/addon-item-styles.d.ts +2 -0
  3. package/dist/src/WebComponent/FeeCalculator/components/addon-item/addon-item.d.ts +22 -0
  4. package/dist/src/WebComponent/FeeCalculator/components/addon-item/index.d.ts +1 -0
  5. package/dist/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout-styles.d.ts +2 -0
  6. package/dist/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout.d.ts +34 -0
  7. package/dist/src/WebComponent/FeeCalculator/components/fee-card/fee-card-styles.d.ts +2 -0
  8. package/dist/src/WebComponent/FeeCalculator/components/fee-card/fee-card.d.ts +21 -0
  9. package/dist/src/WebComponent/FeeCalculator/components/fee-item/fee-item-styles.d.ts +2 -0
  10. package/dist/src/WebComponent/FeeCalculator/components/fee-item/fee-item.d.ts +13 -0
  11. package/dist/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector-styles.d.ts +2 -0
  12. package/dist/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.d.ts +33 -0
  13. package/dist/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card-styles.d.ts +2 -0
  14. package/dist/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card.d.ts +18 -0
  15. package/dist/src/WebComponent/FeeCalculator/components/index.d.ts +5 -0
  16. package/dist/src/WebComponent/FeeCalculator/components/promo-card/promo-card-styles.d.ts +2 -0
  17. package/dist/src/WebComponent/FeeCalculator/components/promo-card/promo-card.d.ts +13 -0
  18. package/dist/src/WebComponent/FeeCalculator/constants.d.ts +2 -0
  19. package/dist/src/WebComponent/FeeCalculator/fee-calculator-styles.d.ts +1 -0
  20. package/dist/src/WebComponent/FeeCalculator/fee-calculator.d.ts +59 -0
  21. package/dist/src/WebComponent/FeeCalculator/index.d.ts +2 -0
  22. package/dist/src/WebComponent/FeeCalculator/model/building-fee.d.ts +80 -0
  23. package/dist/src/WebComponent/FeeCalculator/model/transaction-category.d.ts +23 -0
  24. package/dist/src/WebComponent/LeadSourceClient.d.ts +46 -0
  25. package/dist/src/WebComponent/OfficeHours.d.ts +21 -0
  26. package/dist/src/WebComponent/Scheduler/date-picker.d.ts +28 -0
  27. package/dist/src/WebComponent/Scheduler/time-picker.d.ts +14 -0
  28. package/dist/src/WebComponent/Scheduler/tour-scheduler.d.ts +100 -0
  29. package/dist/src/WebComponent/Scheduler/tour-type-option.d.ts +13 -0
  30. package/dist/src/WebComponent/Scheduler/tourSchedulerStyles.d.ts +1 -0
  31. package/dist/src/WebComponent/actions/InputStyles.d.ts +1 -0
  32. package/dist/src/WebComponent/actions/action-confirm-button.d.ts +13 -0
  33. package/dist/src/WebComponent/actions/call-us-window.d.ts +37 -0
  34. package/dist/src/WebComponent/actions/collapse-expand-button.d.ts +8 -0
  35. package/dist/src/WebComponent/actions/details-window.d.ts +14 -0
  36. package/dist/src/WebComponent/actions/email-us-window.d.ts +46 -0
  37. package/dist/src/WebComponent/actions/formatPhoneNumber.d.ts +17 -0
  38. package/dist/src/WebComponent/actions/minimize-expand-button.d.ts +8 -0
  39. package/dist/src/WebComponent/chat-additional-actions.d.ts +28 -0
  40. package/dist/src/WebComponent/health-chat.d.ts +47 -0
  41. package/dist/src/WebComponent/healthchat-styles.d.ts +1 -0
  42. package/dist/src/WebComponent/icons/ApplyOutlineIcon.d.ts +2 -0
  43. package/dist/src/WebComponent/icons/BookTourOutlineIcon.d.ts +2 -0
  44. package/dist/src/WebComponent/icons/CalculatorOutlineIcon.d.ts +2 -0
  45. package/dist/src/WebComponent/icons/ChatOutlineIcon.d.ts +2 -0
  46. package/dist/src/WebComponent/icons/ChevronLeftIcon.d.ts +2 -0
  47. package/dist/src/WebComponent/icons/ChevronRightIcon.d.ts +2 -0
  48. package/dist/src/WebComponent/icons/ContactResidentIcon.d.ts +2 -0
  49. package/dist/src/WebComponent/icons/DollarOutlineIcon.d.ts +3 -0
  50. package/dist/src/WebComponent/icons/EmailOutlineIcon.d.ts +2 -0
  51. package/dist/src/WebComponent/icons/HeyThereEmojiIcon.d.ts +2 -0
  52. package/dist/src/WebComponent/icons/PhoneOutlineIcon.d.ts +2 -0
  53. package/dist/src/WebComponent/icons/SendMessageIcon.d.ts +3 -0
  54. package/dist/src/WebComponent/icons/TourSelfGuidedIcon.d.ts +2 -0
  55. package/dist/src/WebComponent/icons/TourVirtuallyIcon.d.ts +2 -0
  56. package/dist/src/WebComponent/icons/TourWithAgentIcon.d.ts +2 -0
  57. package/dist/src/WebComponent/icons/XOutlineIcon.d.ts +2 -0
  58. package/dist/src/WebComponent/index.d.ts +2 -0
  59. package/dist/src/WebComponent/launcher/Launcher.d.ts +98 -0
  60. package/dist/src/WebComponent/launcher/launcherStyles.d.ts +1 -0
  61. package/dist/src/WebComponent/launcher/mobile-launcher.d.ts +27 -0
  62. package/dist/src/WebComponent/launcher/typeEmojiStyles.d.ts +1 -0
  63. package/dist/src/WebComponent/launcher/typeMiniStyles.d.ts +1 -0
  64. package/dist/src/WebComponent/launcher/typeMobileStyles.d.ts +1 -0
  65. package/dist/src/WebComponent/leasing-chat-styles.d.ts +1 -0
  66. package/dist/src/WebComponent/me-chat.d.ts +91 -0
  67. package/dist/src/WebComponent/me-select.d.ts +24 -0
  68. package/dist/src/WebComponent/mega-loader.d.ts +7 -0
  69. package/dist/src/WebComponent/mini-loader.d.ts +5 -0
  70. package/dist/src/WebComponent/pubnub-chat-styles.d.ts +1 -0
  71. package/dist/src/WebComponent/pubnub-chat.d.ts +49 -0
  72. package/dist/src/WebComponent/pubnub-media.d.ts +14 -0
  73. package/dist/src/WebComponent/pubnub-message-styles.d.ts +1 -0
  74. package/dist/src/WebComponent/pubnub-message.d.ts +39 -0
  75. package/dist/src/WebComponent/simple-launcher/simple-launcher-styles.d.ts +1 -0
  76. package/dist/src/WebComponent/simple-launcher/simple-launcher.d.ts +12 -0
  77. package/dist/src/WebComponent/utilities-chat.d.ts +47 -0
  78. package/dist/src/WebComponent/utilities-styles.d.ts +1 -0
  79. package/dist/src/WebComponent/utils.d.ts +31 -0
  80. package/dist/src/analytics.d.ts +64 -0
  81. package/dist/src/disclaimers.d.ts +8 -0
  82. package/dist/src/fetchBuildingABTestType.d.ts +8 -0
  83. package/dist/src/fetchBuildingInfo.d.ts +57 -0
  84. package/dist/src/fetchBuildingWebchatView.d.ts +123 -0
  85. package/dist/src/fetchFeatureFlag.d.ts +14 -0
  86. package/dist/src/fetchLeadSources.d.ts +4 -0
  87. package/dist/src/fetchPhoneNumberFromSource.d.ts +6 -0
  88. package/dist/src/getAvailabilities.d.ts +45 -0
  89. package/dist/src/getBuildingPhoneNumber.d.ts +1 -0
  90. package/dist/src/getShouldAllowScheduling.d.ts +1 -0
  91. package/dist/src/getShouldShowWebchat.d.ts +3 -0
  92. package/dist/src/getTimezoneString.d.ts +1 -0
  93. package/dist/src/globals.d.ts +1 -0
  94. package/dist/src/gtm.d.ts +6 -0
  95. package/dist/src/handleChatId.d.ts +11 -0
  96. package/dist/src/insertDNIIntoWebsite.d.ts +5 -0
  97. package/dist/src/insertLeadSourceIntoSchedulerLinks.d.ts +4 -0
  98. package/dist/src/main/MEChat.d.ts +74 -0
  99. package/dist/src/main/utils.d.ts +2 -0
  100. package/dist/src/postLeadSources.d.ts +3 -0
  101. package/dist/src/rentgrata.d.ts +4 -0
  102. package/dist/src/replaceSelectButtonsWithNewLink.d.ts +5 -0
  103. package/dist/src/services/fees/calculateQuote.d.ts +52 -0
  104. package/dist/src/services/fees/fetchBuildingFees.d.ts +24 -0
  105. package/dist/src/services/fees/fetchBuildingFloorplans.d.ts +21 -0
  106. package/dist/src/services/fees/utils.d.ts +1 -0
  107. package/dist/src/svgIcons.d.ts +5 -0
  108. package/dist/src/themes.d.ts +5 -0
  109. package/dist/src/types/rest-sdk.types.d.ts +11 -0
  110. package/dist/src/types/webchat-no-show-reason.d.ts +1 -0
  111. package/dist/src/utils.d.ts +13 -0
  112. package/package.json +1 -1
  113. package/public/dist/index.js +384 -179
  114. package/src/MyPubnub.ts +792 -0
  115. package/src/WebComponent/FeeCalculator/components/addon-item/addon-item-styles.ts +79 -0
  116. package/src/WebComponent/FeeCalculator/components/addon-item/addon-item.ts +121 -0
  117. package/src/WebComponent/FeeCalculator/components/addon-item/index.ts +1 -0
  118. package/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout-styles.ts +127 -0
  119. package/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout.ts +191 -0
  120. package/src/WebComponent/FeeCalculator/components/fee-card/fee-card-styles.ts +65 -0
  121. package/src/WebComponent/FeeCalculator/components/fee-card/fee-card.ts +91 -0
  122. package/src/WebComponent/FeeCalculator/components/fee-item/fee-item-styles.ts +44 -0
  123. package/src/WebComponent/FeeCalculator/components/fee-item/fee-item.ts +38 -0
  124. package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector-styles.ts +144 -0
  125. package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.ts +241 -0
  126. package/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card-styles.ts +74 -0
  127. package/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card.ts +72 -0
  128. package/src/WebComponent/FeeCalculator/components/index.ts +5 -0
  129. package/src/WebComponent/FeeCalculator/components/promo-card/promo-card-styles.ts +39 -0
  130. package/src/WebComponent/FeeCalculator/components/promo-card/promo-card.ts +39 -0
  131. package/src/WebComponent/FeeCalculator/constants.ts +3 -0
  132. package/src/WebComponent/FeeCalculator/fee-calculator-styles.ts +334 -0
  133. package/src/WebComponent/FeeCalculator/fee-calculator.ts +369 -0
  134. package/src/WebComponent/FeeCalculator/index.ts +4 -0
  135. package/src/WebComponent/FeeCalculator/model/building-fee.ts +120 -0
  136. package/src/WebComponent/FeeCalculator/model/transaction-category.ts +23 -0
  137. package/src/WebComponent/LeadSourceClient.ts +332 -0
  138. package/src/WebComponent/MEChat.css +5 -0
  139. package/src/WebComponent/OfficeHours.ts +73 -0
  140. package/src/WebComponent/Scheduler/date-picker.ts +405 -0
  141. package/src/WebComponent/Scheduler/time-picker.ts +190 -0
  142. package/src/WebComponent/Scheduler/tour-scheduler.ts +1373 -0
  143. package/src/WebComponent/Scheduler/tour-type-option.ts +112 -0
  144. package/src/WebComponent/Scheduler/tourSchedulerStyles.ts +418 -0
  145. package/src/WebComponent/actions/InputStyles.ts +57 -0
  146. package/src/WebComponent/actions/action-confirm-button.ts +125 -0
  147. package/src/WebComponent/actions/call-us-window.ts +445 -0
  148. package/src/WebComponent/actions/collapse-expand-button.ts +65 -0
  149. package/src/WebComponent/actions/details-window.ts +150 -0
  150. package/src/WebComponent/actions/email-us-window.ts +555 -0
  151. package/src/WebComponent/actions/formatPhoneNumber.ts +72 -0
  152. package/src/WebComponent/actions/minimize-expand-button.ts +93 -0
  153. package/src/WebComponent/chat-additional-actions.ts +135 -0
  154. package/src/WebComponent/health-chat.ts +270 -0
  155. package/src/WebComponent/healthchat-styles.ts +119 -0
  156. package/src/WebComponent/icons/ApplyOutlineIcon.ts +22 -0
  157. package/src/WebComponent/icons/BookTourOutlineIcon.ts +13 -0
  158. package/src/WebComponent/icons/CalculatorOutlineIcon.ts +22 -0
  159. package/src/WebComponent/icons/ChatOutlineIcon.ts +10 -0
  160. package/src/WebComponent/icons/ChevronLeftIcon.ts +7 -0
  161. package/src/WebComponent/icons/ChevronRightIcon.ts +7 -0
  162. package/src/WebComponent/icons/ContactResidentIcon.ts +9 -0
  163. package/src/WebComponent/icons/DollarOutlineIcon.ts +18 -0
  164. package/src/WebComponent/icons/EmailOutlineIcon.ts +7 -0
  165. package/src/WebComponent/icons/HeyThereEmojiIcon.ts +12 -0
  166. package/src/WebComponent/icons/PhoneOutlineIcon.ts +7 -0
  167. package/src/WebComponent/icons/SendMessageIcon.ts +17 -0
  168. package/src/WebComponent/icons/TourSelfGuidedIcon.ts +17 -0
  169. package/src/WebComponent/icons/TourVirtuallyIcon.ts +17 -0
  170. package/src/WebComponent/icons/TourWithAgentIcon.ts +17 -0
  171. package/src/WebComponent/icons/XOutlineIcon.ts +8 -0
  172. package/src/WebComponent/index.ts +2 -0
  173. package/src/WebComponent/launcher/Launcher.ts +1282 -0
  174. package/src/WebComponent/launcher/launcherStyles.ts +500 -0
  175. package/src/WebComponent/launcher/mobile-launcher.ts +162 -0
  176. package/src/WebComponent/launcher/typeEmojiStyles.ts +161 -0
  177. package/src/WebComponent/launcher/typeMiniStyles.ts +60 -0
  178. package/src/WebComponent/launcher/typeMobileStyles.ts +50 -0
  179. package/src/WebComponent/leasing-chat-styles.ts +114 -0
  180. package/src/WebComponent/me-chat.ts +1262 -0
  181. package/src/WebComponent/me-select.ts +322 -0
  182. package/src/WebComponent/mega-loader.ts +36 -0
  183. package/src/WebComponent/mini-loader.ts +28 -0
  184. package/src/WebComponent/pubnub-chat-styles.ts +204 -0
  185. package/src/WebComponent/pubnub-chat.ts +928 -0
  186. package/src/WebComponent/pubnub-media.ts +208 -0
  187. package/src/WebComponent/pubnub-message-styles.ts +54 -0
  188. package/src/WebComponent/pubnub-message.ts +431 -0
  189. package/src/WebComponent/simple-launcher/simple-launcher-styles.ts +34 -0
  190. package/src/WebComponent/simple-launcher/simple-launcher.ts +100 -0
  191. package/src/WebComponent/utilities-chat.ts +270 -0
  192. package/src/WebComponent/utilities-styles.ts +110 -0
  193. package/src/WebComponent/utils.ts +82 -0
  194. package/src/analytics.ts +217 -0
  195. package/src/assetUrls.ts +6 -0
  196. package/src/disclaimers.ts +58 -0
  197. package/src/fetchBuildingABTestType.ts +21 -0
  198. package/src/fetchBuildingInfo.ts +87 -0
  199. package/src/fetchBuildingWebchatView.ts +156 -0
  200. package/src/fetchFeatureFlag.ts +250 -0
  201. package/src/fetchLeadSources.ts +98 -0
  202. package/src/fetchPhoneNumberFromSource.ts +31 -0
  203. package/src/fetchWebchatPreferences.ts +54 -0
  204. package/src/getAvailabilities.ts +179 -0
  205. package/src/getBuildingPhoneNumber.ts +26 -0
  206. package/src/getShouldAllowScheduling.ts +16 -0
  207. package/src/getShouldShowWebchat.ts +114 -0
  208. package/src/getTimezoneString.ts +39 -0
  209. package/src/globals.ts +1 -0
  210. package/src/gtm.ts +17 -0
  211. package/src/handleChatId.ts +101 -0
  212. package/src/insertDNIIntoWebsite.ts +146 -0
  213. package/src/insertLeadSourceIntoSchedulerLinks.ts +71 -0
  214. package/src/main/MEChat.test.ts +110 -0
  215. package/src/main/MEChat.ts +404 -0
  216. package/src/main/utils.ts +70 -0
  217. package/src/postLeadSources.ts +44 -0
  218. package/src/rentgrata.ts +74 -0
  219. package/src/replaceSelectButtonsWithNewLink.ts +69 -0
  220. package/src/services/fees/calculateQuote.ts +135 -0
  221. package/src/services/fees/fetchBuildingFees.ts +63 -0
  222. package/src/services/fees/fetchBuildingFloorplans.ts +74 -0
  223. package/src/services/fees/utils.ts +4 -0
  224. package/src/svgIcons.ts +14 -0
  225. package/src/themes.ts +65 -0
  226. package/src/types/rest-sdk.types.ts +13 -0
  227. package/src/types/webchat-no-show-reason.ts +6 -0
  228. package/src/utils.ts +121 -0
@@ -0,0 +1,114 @@
1
+ import { logSignal } from "./analytics";
2
+ import { BuildingWebchatView } from "./fetchBuildingWebchatView";
3
+ import { fetchFeatureFlagMaintenanceMode } from "./fetchFeatureFlag";
4
+ import { WebchatNoShowReason } from "./types/webchat-no-show-reason";
5
+
6
+ const getShouldShowWebchat = async (
7
+ buildingWebchatView: BuildingWebchatView | null,
8
+ buildingSlug: string,
9
+ orgSlug: string
10
+ ): Promise<boolean> => {
11
+ const sampleRateForWebchat = 0.01;
12
+
13
+ if (!buildingWebchatView) {
14
+ // eslint-disable-next-line no-console
15
+ console.warn("MeetElise Chat will NOT appear. Building does NOT exist.");
16
+ log(
17
+ orgSlug,
18
+ buildingSlug,
19
+ true,
20
+ false,
21
+ "building_does_not_exist",
22
+ sampleRateForWebchat
23
+ );
24
+ return false;
25
+ }
26
+ if (!buildingWebchatView.launchedDateTime) {
27
+ // eslint-disable-next-line no-console
28
+ console.warn(
29
+ "MeetElise Chat will NOT appear. Building is NOT launched (based on launched date time)."
30
+ );
31
+ log(
32
+ orgSlug,
33
+ buildingSlug,
34
+ true,
35
+ false,
36
+ "building_not_launched",
37
+ sampleRateForWebchat
38
+ );
39
+ return false;
40
+ }
41
+
42
+ if (!buildingWebchatView.active) {
43
+ // eslint-disable-next-line no-console
44
+ console.warn("MeetElise Chat will NOT appear. Building is NOT active.");
45
+ log(
46
+ orgSlug,
47
+ buildingSlug,
48
+ true,
49
+ false,
50
+ "building_not_active",
51
+ sampleRateForWebchat
52
+ );
53
+ return false;
54
+ }
55
+ if (!buildingWebchatView.webchatScopeConfigured) {
56
+ // eslint-disable-next-line no-console
57
+ console.warn(
58
+ "MeetElise Chat will NOT appear. Building is NOT webchat scope configured."
59
+ );
60
+ log(
61
+ orgSlug,
62
+ buildingSlug,
63
+ true,
64
+ false,
65
+ "building_not_webchat_scope_configured",
66
+ sampleRateForWebchat
67
+ );
68
+ return false;
69
+ }
70
+
71
+ const leasingMaintenanceMode = await fetchFeatureFlagMaintenanceMode(
72
+ buildingSlug
73
+ );
74
+ // https://app.launchdarkly.com/projects/default/flags/webchat-leasing-in-maintenance-mode/targeting?env=production&selected-env=production
75
+ if (leasingMaintenanceMode) {
76
+ // eslint-disable-next-line no-console
77
+ console.warn(
78
+ "MeetElise Chat will NOT appear. Chat is in maintenance mode."
79
+ );
80
+ log(
81
+ orgSlug,
82
+ buildingSlug,
83
+ true,
84
+ false,
85
+ "building_in_maintenance_mode",
86
+ sampleRateForWebchat
87
+ );
88
+ return false;
89
+ }
90
+ return true;
91
+ };
92
+
93
+ const log = (
94
+ orgSlug: string,
95
+ buildingSlug: string,
96
+ isPixelOnSite = true,
97
+ isAnyWebchatShowing = false,
98
+ webchatNoShowReason: WebchatNoShowReason,
99
+ sampleRate = 0.01
100
+ ) =>
101
+ logSignal({
102
+ params: {
103
+ org_slug: orgSlug,
104
+ building_slug: buildingSlug,
105
+ is_pixel_on_site: isPixelOnSite,
106
+ is_any_webchat_showing: isAnyWebchatShowing,
107
+ extra_data: {
108
+ webchat_no_show_reason: webchatNoShowReason,
109
+ },
110
+ },
111
+ sampleRate,
112
+ });
113
+
114
+ export default getShouldShowWebchat;
@@ -0,0 +1,39 @@
1
+ const isDaylightSavingTime = (date: Date): boolean => {
2
+ const jan = new Date(date.getFullYear(), 0, 1);
3
+ const jul = new Date(date.getFullYear(), 6, 1);
4
+ const stdTimezoneOffset = Math.max(
5
+ jan.getTimezoneOffset(),
6
+ jul.getTimezoneOffset()
7
+ );
8
+
9
+ return date.getTimezoneOffset() < stdTimezoneOffset;
10
+ };
11
+
12
+ export const getTimezoneAbbreviation = (): string => {
13
+ const date = new Date();
14
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
15
+ const isDST = isDaylightSavingTime(date);
16
+
17
+ switch (timeZone) {
18
+ case "America/New_York":
19
+ return isDST ? "EDT" : "EST";
20
+ case "America/Chicago":
21
+ return isDST ? "CDT" : "CST";
22
+ case "America/Denver":
23
+ return isDST ? "MDT" : "MST";
24
+ case "America/Los_Angeles":
25
+ return isDST ? "PDT" : "PST";
26
+ case "America/Anchorage":
27
+ return isDST ? "AKDT" : "AKST";
28
+ case "America/Honolulu":
29
+ return "HST";
30
+ case "America/Phoenix":
31
+ return "MST";
32
+ case "America/Indiana/Indianapolis":
33
+ return isDST ? "EDT" : "EST";
34
+ case "America/Indiana/Knox":
35
+ return isDST ? "CDT" : "CST";
36
+ default:
37
+ return "Unknown";
38
+ }
39
+ };
package/src/globals.ts ADDED
@@ -0,0 +1 @@
1
+ export const BASE_DOMAIN = "https://app.meetelise.com";
package/src/gtm.ts ADDED
@@ -0,0 +1,17 @@
1
+ declare global {
2
+ interface Window {
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ dataLayer: any[];
5
+ }
6
+ }
7
+
8
+ export const pushGtmEvent = (
9
+ eventName: string,
10
+ event: Record<string, unknown> = {}
11
+ ): void => {
12
+ window.dataLayer = window.dataLayer || [];
13
+ window.dataLayer.push({
14
+ event: eventName,
15
+ ...event,
16
+ });
17
+ };
@@ -0,0 +1,101 @@
1
+ import parseISO from "date-fns/parseISO";
2
+ import { v4 as uuid } from "uuid";
3
+ import formatISO from "date-fns/formatISO";
4
+ import { isTimestampExpired } from "./utils";
5
+ import isBefore from "date-fns/isBefore";
6
+
7
+ export interface ChatStorageKey {
8
+ leadId: string | null;
9
+ timestamp: Date | null;
10
+ buildingSlug: string | null;
11
+ initiatedChat: boolean;
12
+ }
13
+
14
+ export const ttlHours = 24;
15
+
16
+ export const clearChatStorageKey = (buildingSlug: string): void =>
17
+ localStorage.removeItem("com.elise.webchat.slug=" + buildingSlug);
18
+
19
+ export const createChatStorageKey = (
20
+ buildingSlug: string,
21
+ withChatinitialized: boolean,
22
+ leadId?: string
23
+ ): ChatStorageKey => {
24
+ const storageTimestamp = formatISO(new Date());
25
+
26
+ // must preface with lead for BE to extract lead id
27
+ const leadUserId = leadId ? leadId : `lead_${uuid()}`;
28
+ localStorage.setItem(
29
+ "com.elise.webchat.slug=" + buildingSlug,
30
+ JSON.stringify({
31
+ buildingSlug: buildingSlug,
32
+ leadId: leadUserId,
33
+ timestamp: storageTimestamp,
34
+ initiatedChat: withChatinitialized,
35
+ })
36
+ );
37
+ return {
38
+ leadId: leadUserId,
39
+ timestamp: parseISO(storageTimestamp),
40
+ buildingSlug: buildingSlug,
41
+ initiatedChat: withChatinitialized,
42
+ };
43
+ };
44
+
45
+ export const getChatStorageKey = (buildingSlug: string): ChatStorageKey => {
46
+ const eliseaiLocalStorageValue = localStorage.getItem(
47
+ "com.elise.webchat.slug=" + buildingSlug
48
+ );
49
+ if (eliseaiLocalStorageValue) {
50
+ try {
51
+ const eliseaiLocalStorageValueParsed = JSON.parse(
52
+ eliseaiLocalStorageValue
53
+ );
54
+ const newStorageKey = {
55
+ leadId: eliseaiLocalStorageValueParsed.leadId,
56
+ timestamp: new Date(eliseaiLocalStorageValueParsed.timestamp),
57
+ buildingSlug: eliseaiLocalStorageValueParsed.buildingSlug,
58
+ initiatedChat: eliseaiLocalStorageValueParsed.initiatedChat,
59
+ };
60
+ if (isChatKeyValid(buildingSlug, newStorageKey)) {
61
+ return newStorageKey;
62
+ }
63
+ } catch (_) {
64
+ // eslint-disable-next-line no-console
65
+ console.warn("Error getting chat storage key");
66
+ }
67
+ }
68
+
69
+ return {
70
+ leadId: null,
71
+ timestamp: null,
72
+ buildingSlug: null,
73
+ initiatedChat: false,
74
+ };
75
+ };
76
+ export const isChatKeyValid = (
77
+ buildingSlug: string,
78
+ storageValue: ChatStorageKey
79
+ ): boolean => {
80
+ // If we want to do force invalidation
81
+ try {
82
+ if (storageValue.timestamp && storageValue.initiatedChat) {
83
+ const topBoundaryTimestamp = new Date("2024-06-06T21:30:00Z");
84
+ if (isBefore(storageValue.timestamp, topBoundaryTimestamp)) {
85
+ return false;
86
+ }
87
+ }
88
+ } catch (_) {
89
+ // eslint-disable-next-line no-console
90
+ console.warn("Error checking chat storage key validity");
91
+ }
92
+
93
+ if (
94
+ storageValue.buildingSlug !== buildingSlug ||
95
+ !storageValue.leadId ||
96
+ !storageValue.timestamp
97
+ ) {
98
+ return false;
99
+ }
100
+ return !isTimestampExpired(storageValue.timestamp, ttlHours);
101
+ };
@@ -0,0 +1,146 @@
1
+ /**
2
+ * General script to find all phone numbers on a page and replace them with a
3
+ * DNI phone number.
4
+ */
5
+
6
+ import { LogType, sendLoggingEvent } from "./analytics";
7
+
8
+ export const insertDNIIntoWebsite = (
9
+ cleanPhoneNumber: string, // format of 1234567890
10
+ orgSlug: string,
11
+ buildingSlug?: string
12
+ ): number => {
13
+ const newHrefNumber = `tel:${cleanPhoneNumber}`;
14
+ const newHrefSmsNumber = `sms:${cleanPhoneNumber}`;
15
+ const newWhatsAppNumber = `whatsapp://send?phone=${cleanPhoneNumber}}`;
16
+ const newFacetimeNumber = `facetime:${cleanPhoneNumber}`;
17
+ const newFacetimeAudioNumber = `facetime-audio:${cleanPhoneNumber}`;
18
+
19
+ const phoneNumberPattern = /(?:\(\d{3}\)\s|\d{3}-)\d{3}-\d{4}/g;
20
+ const hrefNumberPattern = /(tel|sms):(?:\(\d{3}\)\s|\d{3}-)\d{3}-\d{4}/g;
21
+
22
+ const whatsappNumberPattern = /whatsapp:\/\/send\?phone=\d+/g;
23
+ const facetimeNumberPattern = /(facetime|facetime-audio):\d+/g;
24
+
25
+ const allHTMLItems = document.body.getElementsByTagName("*");
26
+
27
+ let foundPhoneNumber = false;
28
+
29
+ // from a phone format of 1234567890 to (123) 456-7890
30
+ const newPhoneNumber = cleanPhoneNumber.replace(
31
+ /(\d{3})(\d{3})(\d{4})/,
32
+ "($1) $2-$3"
33
+ );
34
+
35
+ let shouldLogTextInsertionError = false;
36
+ let shouldLogHrefInsertionError = false;
37
+
38
+ let totalReplacements = 0;
39
+
40
+ for (let i = 0; i < allHTMLItems.length; i++) {
41
+ if (allHTMLItems[i].nodeType !== Node.ELEMENT_NODE) {
42
+ continue;
43
+ }
44
+
45
+ // Handles the actual display phone number
46
+ if (
47
+ allHTMLItems[i].childNodes.length === 1 &&
48
+ allHTMLItems[i].childNodes[0].nodeType == Node.TEXT_NODE
49
+ ) {
50
+ const oldInnerHTML = allHTMLItems[i].innerHTML;
51
+ const newInnerHTML = oldInnerHTML.replace(
52
+ phoneNumberPattern,
53
+ newPhoneNumber
54
+ );
55
+ if (oldInnerHTML !== newInnerHTML) {
56
+ totalReplacements++;
57
+ }
58
+ allHTMLItems[i].innerHTML = newInnerHTML;
59
+
60
+ foundPhoneNumber = true;
61
+
62
+ if (!shouldLogTextInsertionError) {
63
+ shouldLogTextInsertionError = true;
64
+ }
65
+ }
66
+
67
+ // Handles the href phone number (so when you click the link, it will call the phone number)
68
+ if (allHTMLItems[i].hasAttribute("href")) {
69
+ const href = allHTMLItems[i].getAttribute("href");
70
+ if (!href) {
71
+ continue;
72
+ }
73
+
74
+ let newHrefValue = "";
75
+ let currentPattern = hrefNumberPattern;
76
+
77
+ if (href.startsWith("sms:")) {
78
+ newHrefValue = newHrefSmsNumber;
79
+ } else if (href.startsWith("whatsapp:")) {
80
+ newHrefValue = newWhatsAppNumber;
81
+ currentPattern = whatsappNumberPattern;
82
+ } else if (href.startsWith("facetime:")) {
83
+ newHrefValue = newFacetimeNumber;
84
+ currentPattern = facetimeNumberPattern;
85
+ } else if (href.startsWith("facetime-audio:")) {
86
+ newHrefValue = newFacetimeAudioNumber;
87
+ currentPattern = facetimeNumberPattern;
88
+ } else {
89
+ newHrefValue = newHrefNumber;
90
+ }
91
+
92
+ const newHref = href.replace(currentPattern, newHrefValue);
93
+ allHTMLItems[i].setAttribute("href", newHref);
94
+
95
+ if (!shouldLogHrefInsertionError) {
96
+ shouldLogHrefInsertionError = true;
97
+ }
98
+ }
99
+ }
100
+
101
+ // We could make these logs more specific but for now we'll just log the
102
+ // if there is even a single error to limit the error logs we throw
103
+
104
+ if (shouldLogTextInsertionError) {
105
+ sendLoggingEvent({
106
+ logTitle: "DNI_WEBSITE_INSERTION",
107
+ logData: {
108
+ type: "text-insertion",
109
+ newPhoneNumber,
110
+ website: window.location.href,
111
+ },
112
+ logType: LogType.info,
113
+ buildingSlug,
114
+ orgSlug,
115
+ });
116
+ }
117
+
118
+ if (shouldLogHrefInsertionError) {
119
+ sendLoggingEvent({
120
+ logTitle: "DNI_WEBSITE_INSERTION",
121
+ logData: {
122
+ type: "href-insertion",
123
+ newPhoneNumber,
124
+ website: window.location.href,
125
+ },
126
+ logType: LogType.info,
127
+ buildingSlug,
128
+ orgSlug,
129
+ });
130
+ }
131
+
132
+ if (!foundPhoneNumber) {
133
+ sendLoggingEvent({
134
+ logTitle: "DNI_WEBSITE_INSERTION",
135
+ logData: {
136
+ type: "no-phone-number-found",
137
+ website: window.location.href,
138
+ },
139
+ logType: LogType.warn,
140
+ buildingSlug,
141
+ orgSlug,
142
+ });
143
+ }
144
+
145
+ return totalReplacements;
146
+ };
@@ -0,0 +1,71 @@
1
+ // DEPRECATED: This function is no longer used. It was used to insert the lead source into the scheduler links.
2
+ // We now prevent the redirect and force tour SST widget to open instead in replaceSSTLinkWithTourWidgetTrigger.ts.
3
+ export const insertLeadSourceIntoSchedulerLinks = (
4
+ leadSource: string
5
+ ): void => {
6
+ const links = document.querySelectorAll("a");
7
+ links.forEach(function (link) {
8
+ const href = link.getAttribute("href");
9
+ if (href && href.startsWith("https://app.meetelise.com/")) {
10
+ const separator = href.includes("?") ? "&" : "?";
11
+ link.setAttribute(
12
+ "href",
13
+ href +
14
+ separator +
15
+ `eliseParsedLeadSource=${encodeURIComponent(leadSource)}`
16
+ );
17
+ }
18
+ });
19
+ };
20
+
21
+ export const replaceSSTLinkWithTourWidgetTrigger = (
22
+ handleTourClicked: (e: MouseEvent) => void
23
+ ): void => {
24
+ const sstRedirectElements = document.querySelectorAll("a");
25
+ sstRedirectElements.forEach(function (element) {
26
+ const href = element.getAttribute("href");
27
+ if (href && href.startsWith("https://app.meetelise.com/")) {
28
+ element.addEventListener("click", (event) => {
29
+ event.preventDefault(); // Prevents the default href redirect
30
+ handleTourClicked(event as MouseEvent);
31
+ });
32
+ }
33
+ });
34
+ };
35
+
36
+ export const replacePageRedirectElementWithTourWidgetTrigger = (
37
+ handleTourClicked: (e: MouseEvent) => void
38
+ ): void => {
39
+ // Gets any elements in format like <a href="/apartments/oh/westerville/schedule-a-tour" class=" ">Schedule a Tour</a>
40
+ const scheduleLinks = document.querySelectorAll('a[href$="schedule-a-tour"]');
41
+ scheduleLinks.forEach((linkElement) => {
42
+ if (!linkElement) {
43
+ return;
44
+ }
45
+ linkElement.addEventListener("click", (event) => {
46
+ event.preventDefault(); // Prevents the default href redirect
47
+ handleTourClicked(event as MouseEvent);
48
+ });
49
+ });
50
+ };
51
+
52
+ export const replaceTourTriggerElementWithTourWidgetTrigger = (
53
+ handleTourClicked: (e: MouseEvent) => void
54
+ ): void => {
55
+ const scheduleLinks = document.querySelectorAll(
56
+ 'a[href^="#leaseleads-tour-open"]'
57
+ );
58
+ scheduleLinks.forEach((linkElement) => {
59
+ if (!linkElement) {
60
+ return;
61
+ }
62
+ const newLink = document.createElement("a");
63
+ newLink.innerHTML = linkElement.innerHTML;
64
+ newLink.style.cursor = "pointer";
65
+ newLink.addEventListener("click", (event) => {
66
+ event.preventDefault();
67
+ handleTourClicked(event as MouseEvent);
68
+ });
69
+ linkElement.parentNode?.replaceChild(newLink, linkElement);
70
+ });
71
+ };
@@ -0,0 +1,110 @@
1
+ import { expect } from "@esm-bundle/chai";
2
+ import { stub, restore } from "sinon/pkg/sinon-esm";
3
+ import MEChat from "../../public/dist/index";
4
+
5
+ const stubResponse = {
6
+ json: stub().resolves({
7
+ id: 42,
8
+ userId: 42.1,
9
+ orgId: 42.2,
10
+ name: "Unit Test Building",
11
+ themeId: null,
12
+ avatarSrc: null,
13
+ avatarType: "",
14
+ userFirstName: "Ella",
15
+ userLastName: "",
16
+ logoSrc:
17
+ "https://eliseusercontent.meetelise.com/building/3660/test-logo.png",
18
+ chatTitle: "Elise",
19
+ chatSubtitle: "Leasing Agent ExtraordinAIre",
20
+ welcomeMessage:
21
+ "Welcome, I'm Elise! If you have any questions about Unit Test Building or would like to schedule a tour, I'm happy to help.",
22
+ systemWelcomeMessage: "I am an AI and may record this conversation!",
23
+ conversationMaintenanceMode: false,
24
+ }),
25
+ };
26
+
27
+ const waitForElementWithSelectorToExist = async (
28
+ selector: string,
29
+ target: Node = document.body
30
+ ): Promise<void> => {
31
+ return new Promise<void>((resolve) => {
32
+ // in case the element already exists
33
+ if (document.querySelector(selector)) {
34
+ resolve();
35
+ }
36
+ const observer = new MutationObserver(() => {
37
+ if (document.querySelector(selector)) {
38
+ resolve();
39
+ }
40
+ });
41
+ observer.observe(target, { subtree: true, childList: true });
42
+ });
43
+ };
44
+
45
+ // const wait = (delay, ...args) =>
46
+ // new Promise((resolve) => setTimeout(resolve, delay, ...args));
47
+
48
+ afterEach(() => {
49
+ restore();
50
+ });
51
+
52
+ it.skip("shows the launcher", async function () {
53
+ // Given an API that returns this building theme
54
+ stub(window, "fetch").resolves(stubResponse);
55
+
56
+ // When I start MEChat
57
+ MEChat.start({
58
+ organization: "unit-test-org",
59
+ building: "unit-test-building",
60
+ });
61
+ await waitForElementWithSelectorToExist(".meetelise-chat.launcher > div");
62
+
63
+ // Then I should see a launcher
64
+ const launcher = document.querySelector<HTMLDivElement>(
65
+ ".meetelise-chat.launcher"
66
+ ).firstChild as HTMLDivElement;
67
+
68
+ // And the popup should be hidden
69
+ const popup = document.querySelector<HTMLSpanElement>(".__talkjs_popup");
70
+ expect(popup).to.be.an.instanceof(HTMLSpanElement);
71
+ const popupStyle = window.getComputedStyle(popup);
72
+ const popupDisplay = popupStyle.getPropertyValue("display");
73
+ expect(popupDisplay).to.equal("none");
74
+
75
+ launcher.click();
76
+ // Without waiting, the popup doesn't open in time for the next assertion
77
+ //await wait.skip(0);
78
+
79
+ // Then the popup should be visible
80
+ const popupStyle2 = window.getComputedStyle(popup);
81
+ const popupDisplay2 = popupStyle2.getPropertyValue("display");
82
+ expect(popupDisplay2).not.to.equal("none");
83
+
84
+ // Ideally, expect welcome message, but we can't select inside the iframe
85
+ // Ideally, expect theme colors, but we can't select inside the iframe
86
+ });
87
+
88
+ it.skip("works via the programmatic interface", async function () {
89
+ // Given an API that returns this building theme
90
+ stub(window, "fetch").resolves(stubResponse);
91
+
92
+ // When I start MEChat
93
+ const chat = MEChat.start({
94
+ organization: "unit-test-org",
95
+ building: "unit-test-building",
96
+ });
97
+
98
+ await waitForElementWithSelectorToExist(".meetelise-chat.launcher > div");
99
+
100
+ // Ideally, verify behavior, but this will at least verify nothing throws
101
+ chat.show();
102
+ chat.hide();
103
+ chat.setTheme({
104
+ avatarInitials: "G",
105
+ });
106
+ chat.open();
107
+ chat.close();
108
+ chat.restartConversation();
109
+ chat.remove();
110
+ });