@meetelise/chat 1.25.1 → 1.25.3

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 (217) hide show
  1. package/package.json +1 -1
  2. package/.prettierignore +0 -2
  3. package/coverage/lcov-report/base.css +0 -224
  4. package/coverage/lcov-report/block-navigation.js +0 -79
  5. package/coverage/lcov-report/favicon.png +0 -0
  6. package/coverage/lcov-report/index.html +0 -111
  7. package/coverage/lcov-report/index.js.html +0 -17093
  8. package/coverage/lcov-report/prettify.css +0 -1
  9. package/coverage/lcov-report/prettify.js +0 -2
  10. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  11. package/coverage/lcov-report/sorter.js +0 -170
  12. package/coverage/lcov.info +0 -9986
  13. package/dist/src/MyPubnub.d.ts +0 -116
  14. package/dist/src/WebComponent/FeeCalculator/components/collapsible-fee-section/collapsible-fee-section-styles.d.ts +0 -2
  15. package/dist/src/WebComponent/FeeCalculator/components/collapsible-fee-section/collapsible-fee-section.d.ts +0 -20
  16. package/dist/src/WebComponent/FeeCalculator/components/fee-item/fee-item-styles.d.ts +0 -2
  17. package/dist/src/WebComponent/FeeCalculator/components/fee-item/fee-item.d.ts +0 -14
  18. package/dist/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector-styles.d.ts +0 -2
  19. package/dist/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.d.ts +0 -17
  20. package/dist/src/WebComponent/FeeCalculator/components/index.d.ts +0 -3
  21. package/dist/src/WebComponent/FeeCalculator/components/promo-card/promo-card-styles.d.ts +0 -2
  22. package/dist/src/WebComponent/FeeCalculator/components/promo-card/promo-card.d.ts +0 -13
  23. package/dist/src/WebComponent/FeeCalculator/fee-calculator-styles.d.ts +0 -1
  24. package/dist/src/WebComponent/FeeCalculator/fee-calculator.d.ts +0 -31
  25. package/dist/src/WebComponent/FeeCalculator/index.d.ts +0 -2
  26. package/dist/src/WebComponent/FeeCalculator/model/building-fee.d.ts +0 -75
  27. package/dist/src/WebComponent/FeeCalculator/model/transaction-category.d.ts +0 -23
  28. package/dist/src/WebComponent/LeadSourceClient.d.ts +0 -46
  29. package/dist/src/WebComponent/OfficeHours.d.ts +0 -21
  30. package/dist/src/WebComponent/Scheduler/date-picker.d.ts +0 -28
  31. package/dist/src/WebComponent/Scheduler/time-picker.d.ts +0 -14
  32. package/dist/src/WebComponent/Scheduler/tour-scheduler.d.ts +0 -99
  33. package/dist/src/WebComponent/Scheduler/tour-type-option.d.ts +0 -13
  34. package/dist/src/WebComponent/Scheduler/tourSchedulerStyles.d.ts +0 -1
  35. package/dist/src/WebComponent/actions/InputStyles.d.ts +0 -1
  36. package/dist/src/WebComponent/actions/action-confirm-button.d.ts +0 -13
  37. package/dist/src/WebComponent/actions/call-us-window.d.ts +0 -37
  38. package/dist/src/WebComponent/actions/collapse-expand-button.d.ts +0 -8
  39. package/dist/src/WebComponent/actions/details-window.d.ts +0 -14
  40. package/dist/src/WebComponent/actions/email-us-window.d.ts +0 -46
  41. package/dist/src/WebComponent/actions/formatPhoneNumber.d.ts +0 -17
  42. package/dist/src/WebComponent/actions/minimize-expand-button.d.ts +0 -8
  43. package/dist/src/WebComponent/chat-additional-actions.d.ts +0 -28
  44. package/dist/src/WebComponent/health-chat.d.ts +0 -47
  45. package/dist/src/WebComponent/healthchat-styles.d.ts +0 -1
  46. package/dist/src/WebComponent/icons/ApplyOutlineIcon.d.ts +0 -2
  47. package/dist/src/WebComponent/icons/BookTourOutlineIcon.d.ts +0 -2
  48. package/dist/src/WebComponent/icons/CalculatorOutlineIcon.d.ts +0 -2
  49. package/dist/src/WebComponent/icons/ChatOutlineIcon.d.ts +0 -2
  50. package/dist/src/WebComponent/icons/ChevronLeftIcon.d.ts +0 -2
  51. package/dist/src/WebComponent/icons/ChevronRightIcon.d.ts +0 -2
  52. package/dist/src/WebComponent/icons/ContactResidentIcon.d.ts +0 -2
  53. package/dist/src/WebComponent/icons/DollarOutlineIcon.d.ts +0 -3
  54. package/dist/src/WebComponent/icons/EmailOutlineIcon.d.ts +0 -2
  55. package/dist/src/WebComponent/icons/HeyThereEmojiIcon.d.ts +0 -2
  56. package/dist/src/WebComponent/icons/PhoneOutlineIcon.d.ts +0 -2
  57. package/dist/src/WebComponent/icons/SendMessageIcon.d.ts +0 -3
  58. package/dist/src/WebComponent/icons/TourSelfGuidedIcon.d.ts +0 -2
  59. package/dist/src/WebComponent/icons/TourVirtuallyIcon.d.ts +0 -2
  60. package/dist/src/WebComponent/icons/TourWithAgentIcon.d.ts +0 -2
  61. package/dist/src/WebComponent/icons/XOutlineIcon.d.ts +0 -2
  62. package/dist/src/WebComponent/index.d.ts +0 -2
  63. package/dist/src/WebComponent/launcher/Launcher.d.ts +0 -98
  64. package/dist/src/WebComponent/launcher/launcherStyles.d.ts +0 -1
  65. package/dist/src/WebComponent/launcher/mobile-launcher.d.ts +0 -26
  66. package/dist/src/WebComponent/launcher/typeEmojiStyles.d.ts +0 -1
  67. package/dist/src/WebComponent/launcher/typeMiniStyles.d.ts +0 -1
  68. package/dist/src/WebComponent/launcher/typeMobileStyles.d.ts +0 -1
  69. package/dist/src/WebComponent/leasing-chat-styles.d.ts +0 -1
  70. package/dist/src/WebComponent/me-chat.d.ts +0 -91
  71. package/dist/src/WebComponent/me-select.d.ts +0 -24
  72. package/dist/src/WebComponent/mini-loader.d.ts +0 -5
  73. package/dist/src/WebComponent/pubnub-chat-styles.d.ts +0 -1
  74. package/dist/src/WebComponent/pubnub-chat.d.ts +0 -49
  75. package/dist/src/WebComponent/pubnub-media.d.ts +0 -14
  76. package/dist/src/WebComponent/pubnub-message-styles.d.ts +0 -1
  77. package/dist/src/WebComponent/pubnub-message.d.ts +0 -39
  78. package/dist/src/WebComponent/simple-launcher/simple-launcher-styles.d.ts +0 -1
  79. package/dist/src/WebComponent/simple-launcher/simple-launcher.d.ts +0 -12
  80. package/dist/src/WebComponent/utilities-chat.d.ts +0 -47
  81. package/dist/src/WebComponent/utilities-styles.d.ts +0 -1
  82. package/dist/src/WebComponent/utils.d.ts +0 -31
  83. package/dist/src/analytics.d.ts +0 -64
  84. package/dist/src/disclaimers.d.ts +0 -8
  85. package/dist/src/fetchBuildingABTestType.d.ts +0 -8
  86. package/dist/src/fetchBuildingInfo.d.ts +0 -57
  87. package/dist/src/fetchBuildingWebchatView.d.ts +0 -122
  88. package/dist/src/fetchFeatureFlag.d.ts +0 -14
  89. package/dist/src/fetchLeadSources.d.ts +0 -4
  90. package/dist/src/fetchPhoneNumberFromSource.d.ts +0 -6
  91. package/dist/src/getAvailabilities.d.ts +0 -44
  92. package/dist/src/getBuildingPhoneNumber.d.ts +0 -1
  93. package/dist/src/getShouldAllowScheduling.d.ts +0 -1
  94. package/dist/src/getShouldShowWebchat.d.ts +0 -3
  95. package/dist/src/getTimezoneString.d.ts +0 -1
  96. package/dist/src/globals.d.ts +0 -1
  97. package/dist/src/gtm.d.ts +0 -6
  98. package/dist/src/handleChatId.d.ts +0 -11
  99. package/dist/src/insertDNIIntoWebsite.d.ts +0 -5
  100. package/dist/src/insertLeadSourceIntoSchedulerLinks.d.ts +0 -4
  101. package/dist/src/main/MEChat.d.ts +0 -74
  102. package/dist/src/main/utils.d.ts +0 -2
  103. package/dist/src/postLeadSources.d.ts +0 -3
  104. package/dist/src/rentgrata.d.ts +0 -4
  105. package/dist/src/replaceSelectButtonsWithNewLink.d.ts +0 -5
  106. package/dist/src/services/fees/fetchBuildingFees.d.ts +0 -3
  107. package/dist/src/svgIcons.d.ts +0 -5
  108. package/dist/src/themes.d.ts +0 -5
  109. package/dist/src/types/rest-sdk.types.d.ts +0 -11
  110. package/dist/src/types/webchat-no-show-reason.d.ts +0 -1
  111. package/dist/src/utils.d.ts +0 -13
  112. package/public/demo/index.html +0 -347
  113. package/public/demo/secret.html +0 -63
  114. package/src/MyPubnub.ts +0 -792
  115. package/src/WebComponent/FeeCalculator/components/collapsible-fee-section/collapsible-fee-section-styles.ts +0 -86
  116. package/src/WebComponent/FeeCalculator/components/collapsible-fee-section/collapsible-fee-section.ts +0 -94
  117. package/src/WebComponent/FeeCalculator/components/fee-item/fee-item-styles.ts +0 -47
  118. package/src/WebComponent/FeeCalculator/components/fee-item/fee-item.ts +0 -50
  119. package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector-styles.ts +0 -46
  120. package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.ts +0 -70
  121. package/src/WebComponent/FeeCalculator/components/index.ts +0 -3
  122. package/src/WebComponent/FeeCalculator/components/promo-card/promo-card-styles.ts +0 -39
  123. package/src/WebComponent/FeeCalculator/components/promo-card/promo-card.ts +0 -39
  124. package/src/WebComponent/FeeCalculator/fee-calculator-styles.ts +0 -280
  125. package/src/WebComponent/FeeCalculator/fee-calculator.ts +0 -256
  126. package/src/WebComponent/FeeCalculator/index.ts +0 -4
  127. package/src/WebComponent/FeeCalculator/model/building-fee.ts +0 -83
  128. package/src/WebComponent/FeeCalculator/model/transaction-category.ts +0 -23
  129. package/src/WebComponent/LeadSourceClient.ts +0 -332
  130. package/src/WebComponent/MEChat.css +0 -5
  131. package/src/WebComponent/OfficeHours.ts +0 -73
  132. package/src/WebComponent/Scheduler/date-picker.ts +0 -405
  133. package/src/WebComponent/Scheduler/time-picker.ts +0 -190
  134. package/src/WebComponent/Scheduler/tour-scheduler.ts +0 -1352
  135. package/src/WebComponent/Scheduler/tour-type-option.ts +0 -112
  136. package/src/WebComponent/Scheduler/tourSchedulerStyles.ts +0 -418
  137. package/src/WebComponent/actions/InputStyles.ts +0 -57
  138. package/src/WebComponent/actions/action-confirm-button.ts +0 -125
  139. package/src/WebComponent/actions/call-us-window.ts +0 -445
  140. package/src/WebComponent/actions/collapse-expand-button.ts +0 -65
  141. package/src/WebComponent/actions/details-window.ts +0 -150
  142. package/src/WebComponent/actions/email-us-window.ts +0 -555
  143. package/src/WebComponent/actions/formatPhoneNumber.ts +0 -72
  144. package/src/WebComponent/actions/minimize-expand-button.ts +0 -93
  145. package/src/WebComponent/chat-additional-actions.ts +0 -135
  146. package/src/WebComponent/health-chat.ts +0 -270
  147. package/src/WebComponent/healthchat-styles.ts +0 -119
  148. package/src/WebComponent/icons/ApplyOutlineIcon.ts +0 -22
  149. package/src/WebComponent/icons/BookTourOutlineIcon.ts +0 -13
  150. package/src/WebComponent/icons/CalculatorOutlineIcon.ts +0 -22
  151. package/src/WebComponent/icons/ChatOutlineIcon.ts +0 -10
  152. package/src/WebComponent/icons/ChevronLeftIcon.ts +0 -7
  153. package/src/WebComponent/icons/ChevronRightIcon.ts +0 -7
  154. package/src/WebComponent/icons/ContactResidentIcon.ts +0 -9
  155. package/src/WebComponent/icons/DollarOutlineIcon.ts +0 -18
  156. package/src/WebComponent/icons/EmailOutlineIcon.ts +0 -7
  157. package/src/WebComponent/icons/HeyThereEmojiIcon.ts +0 -12
  158. package/src/WebComponent/icons/PhoneOutlineIcon.ts +0 -7
  159. package/src/WebComponent/icons/SendMessageIcon.ts +0 -17
  160. package/src/WebComponent/icons/TourSelfGuidedIcon.ts +0 -17
  161. package/src/WebComponent/icons/TourVirtuallyIcon.ts +0 -17
  162. package/src/WebComponent/icons/TourWithAgentIcon.ts +0 -17
  163. package/src/WebComponent/icons/XOutlineIcon.ts +0 -8
  164. package/src/WebComponent/index.ts +0 -2
  165. package/src/WebComponent/launcher/Launcher.ts +0 -1193
  166. package/src/WebComponent/launcher/launcherStyles.ts +0 -500
  167. package/src/WebComponent/launcher/mobile-launcher.ts +0 -159
  168. package/src/WebComponent/launcher/typeEmojiStyles.ts +0 -161
  169. package/src/WebComponent/launcher/typeMiniStyles.ts +0 -60
  170. package/src/WebComponent/launcher/typeMobileStyles.ts +0 -50
  171. package/src/WebComponent/leasing-chat-styles.ts +0 -114
  172. package/src/WebComponent/me-chat.ts +0 -1257
  173. package/src/WebComponent/me-select.ts +0 -322
  174. package/src/WebComponent/mini-loader.ts +0 -28
  175. package/src/WebComponent/pubnub-chat-styles.ts +0 -204
  176. package/src/WebComponent/pubnub-chat.ts +0 -928
  177. package/src/WebComponent/pubnub-media.ts +0 -208
  178. package/src/WebComponent/pubnub-message-styles.ts +0 -54
  179. package/src/WebComponent/pubnub-message.ts +0 -431
  180. package/src/WebComponent/simple-launcher/simple-launcher-styles.ts +0 -34
  181. package/src/WebComponent/simple-launcher/simple-launcher.ts +0 -100
  182. package/src/WebComponent/utilities-chat.ts +0 -270
  183. package/src/WebComponent/utilities-styles.ts +0 -110
  184. package/src/WebComponent/utils.ts +0 -82
  185. package/src/analytics.ts +0 -217
  186. package/src/assetUrls.ts +0 -6
  187. package/src/disclaimers.ts +0 -58
  188. package/src/fetchBuildingABTestType.ts +0 -21
  189. package/src/fetchBuildingInfo.ts +0 -87
  190. package/src/fetchBuildingWebchatView.ts +0 -154
  191. package/src/fetchFeatureFlag.ts +0 -250
  192. package/src/fetchLeadSources.ts +0 -98
  193. package/src/fetchPhoneNumberFromSource.ts +0 -31
  194. package/src/fetchWebchatPreferences.ts +0 -54
  195. package/src/getAvailabilities.ts +0 -174
  196. package/src/getBuildingPhoneNumber.ts +0 -26
  197. package/src/getShouldAllowScheduling.ts +0 -16
  198. package/src/getShouldShowWebchat.ts +0 -114
  199. package/src/getTimezoneString.ts +0 -39
  200. package/src/globals.ts +0 -1
  201. package/src/gtm.ts +0 -17
  202. package/src/handleChatId.ts +0 -101
  203. package/src/insertDNIIntoWebsite.ts +0 -146
  204. package/src/insertLeadSourceIntoSchedulerLinks.ts +0 -71
  205. package/src/main/MEChat.test.ts +0 -110
  206. package/src/main/MEChat.ts +0 -404
  207. package/src/main/utils.ts +0 -70
  208. package/src/postLeadSources.ts +0 -44
  209. package/src/rentgrata.ts +0 -74
  210. package/src/replaceSelectButtonsWithNewLink.ts +0 -68
  211. package/src/services/fees/fetchBuildingFees.ts +0 -28
  212. package/src/svgIcons.ts +0 -14
  213. package/src/themes.ts +0 -65
  214. package/src/types/rest-sdk.types.ts +0 -13
  215. package/src/types/webchat-no-show-reason.ts +0 -6
  216. package/src/utils.ts +0 -121
  217. package/tsconfig.json +0 -84
@@ -1,208 +0,0 @@
1
- import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
2
- import { customElement, property, state } from "lit/decorators.js";
3
- import MyPubnub, { SimpleMediaChatMessage } from "../MyPubnub";
4
- import { classMap } from "lit/directives/class-map.js";
5
- import { InputStyles } from "./actions/InputStyles";
6
- import { pubnubChatStyles } from "./pubnub-chat-styles";
7
-
8
- @customElement("pubnub-media")
9
- export class PubnubMedia extends LitElement {
10
- static styles = [
11
- InputStyles,
12
- pubnubChatStyles,
13
- css`
14
- .carousel {
15
- position: relative;
16
- max-width: 400px;
17
- height: max-content;
18
- min-height: 140px;
19
- margin: auto;
20
- overflow: hidden;
21
- display: flex;
22
- align-items: center;
23
- justify-content: flex-start;
24
- scroll-snap-type: x mandatory;
25
- }
26
- .carousel .image-container {
27
- display: flex;
28
- will-change: transform;
29
- transition: transform 0.5s ease-in-out;
30
- align-items: flex-start;
31
- width: 100%;
32
- }
33
- .carousel img {
34
- width: 100%;
35
- max-width: none;
36
- flex-shrink: 0;
37
- opacity: 0.5;
38
- transition: opacity 0.5s ease;
39
- height: 100%;
40
- object-fit: contain;
41
- display: block;
42
- }
43
- .image-item {
44
- width: 100%;
45
- max-width: none;
46
- flex-shrink: 0;
47
- display: flex;
48
- flex-direction: column;
49
- gap: 10px;
50
- }
51
- .image-link {
52
- width: 100%;
53
- max-width: none;
54
- flex-shrink: 0;
55
- }
56
- .carousel img.active {
57
- opacity: 1;
58
- }
59
- .button {
60
- position: absolute;
61
- top: 50%;
62
- transform: translateY(-50%);
63
- background-color: rgba(0, 0, 0, 0.1);
64
- color: white;
65
- border: none;
66
- border-radius: 2px;
67
- cursor: pointer;
68
- padding: 10px;
69
- z-index: 100;
70
- height: 64px;
71
- width: 32px;
72
- transition: background-color 0.3s ease;
73
- }
74
- .button:hover {
75
- background-color: rgba(0, 0, 0, 0.5);
76
- }
77
- .prev {
78
- left: 2px;
79
- }
80
- .next {
81
- right: 2px;
82
- }
83
- .image-info {
84
- display: flex;
85
- flex-direction: column;
86
- gap: 5px;
87
- }
88
- .image-info p {
89
- margin: 0;
90
- padding: 0;
91
- white-space: wrap;
92
- overflow: hidden;
93
- word-wrap: break-word;
94
- }
95
- .image-info .img-header {
96
- color: #333;
97
- font-size: 14px;
98
- }
99
- .image-info .img-desc {
100
- color: #666;
101
- font-size: 12px;
102
- max-height: 200px;
103
- overflow-y: auto;
104
- }
105
- `,
106
- ];
107
-
108
- @property({
109
- attribute: true,
110
- })
111
- message: SimpleMediaChatMessage | undefined;
112
-
113
- @property({ attribute: true })
114
- myPubnub: MyPubnub | undefined;
115
-
116
- @property({ attribute: true })
117
- onMount: () => void = () => ({});
118
-
119
- updated(changedProperties: PropertyValues<this>): void {
120
- this.onMount();
121
- if (!changedProperties.has("message")) return;
122
- }
123
-
124
- @state()
125
- showMediaAsCarousel = true;
126
-
127
- @state()
128
- activeIndex = 0;
129
-
130
- private prevImage(): void {
131
- if (!this.message) return;
132
- if (this.activeIndex === 0) {
133
- this.activeIndex = this.message.media.length - 1;
134
- } else {
135
- this.activeIndex -= 1;
136
- }
137
- }
138
-
139
- private nextImage(): void {
140
- if (!this.message) return;
141
- if (this.activeIndex === this.message.media.length - 1) {
142
- this.activeIndex = 0;
143
- } else {
144
- this.activeIndex += 1;
145
- }
146
- }
147
-
148
- render(): TemplateResult {
149
- if (!this.message) return html``;
150
-
151
- if (this.showMediaAsCarousel) {
152
- return html`<div class="message-inner-body">
153
- <div class="carousel">
154
- <div
155
- class="image-container"
156
- style="transform: translateX(-${this.activeIndex * 100}%);"
157
- >
158
- ${this.message.media.map(
159
- (image, index) => html`
160
- <div class="image-item">
161
- <a
162
- class="image-link"
163
- href="${image.url}"
164
- target="_blank"
165
- rel="noopener noreferrer"
166
- >
167
- <img
168
- class=${classMap({ active: index === this.activeIndex })}
169
- src=${image.url}
170
- alt=""
171
- />
172
- </a>
173
- <div class="image-info">
174
- ${image.title
175
- ? html`<p class="img-header">${image.title}</p>`
176
- : ""}
177
- ${image.description
178
- ? html`<p class="img-desc">${image.description}</p>`
179
- : ""}
180
- </div>
181
- </div>
182
- `
183
- )}
184
- </div>
185
- ${this.message.media.length > 1
186
- ? html` <button class="button prev" @click=${this.prevImage}>
187
- &#10094;
188
- </button>
189
- <button class="button next" @click=${this.nextImage}>
190
- &#10095;
191
- </button>`
192
- : ""}
193
- </div>
194
- </div>`;
195
- } else {
196
- return html`<div class="message-inner-body">
197
- ${this.message.media.map((image) => {
198
- return html`<a
199
- href="${image.url}"
200
- target="_blank"
201
- rel="noopener noreferrer"
202
- ><img class=${"displayed-message-image"} src=${image.url} alt=""
203
- /></a>`;
204
- })}
205
- </div>`;
206
- }
207
- }
208
- }
@@ -1,54 +0,0 @@
1
- import { css } from "lit";
2
-
3
- export const pubnubMessageStyles = css`
4
- .website-preview {
5
- border: 1px solid rgba(0, 0, 0, 0.2);
6
- border-radius: 8px;
7
- overflow: hidden;
8
- display: flex;
9
- align-items: center;
10
- flex-direction: column;
11
- justify-content: center;
12
-
13
- margin: 0px 6px 6px;
14
- }
15
- .website-preview-image {
16
- max-width: 100%;
17
- max-height: 200px;
18
- width: auto;
19
- height: auto;
20
- }
21
- .website-preview-body {
22
- padding: 8px 0px 12px;
23
- }
24
- .website-preview-title {
25
- font-size: 12px;
26
- font-weight: bold;
27
- margin: 0;
28
- display: -webkit-box;
29
- -webkit-box-orient: vertical;
30
- -webkit-line-clamp: 2;
31
- overflow: hidden;
32
- text-overflow: ellipsis;
33
- max-height: 24px;
34
- }
35
- .website-preview-description {
36
- font-size: 10px;
37
- margin: 0;
38
-
39
- display: -webkit-box;
40
- -webkit-box-orient: vertical;
41
- -webkit-line-clamp: 3;
42
- overflow: hidden;
43
- text-overflow: ellipsis;
44
- max-height: 34px;
45
- }
46
- .redirect-link-preview {
47
- color: inherit;
48
- text-decoration: none;
49
- }
50
-
51
- .hidden {
52
- display: none !important;
53
- }
54
- `;
@@ -1,431 +0,0 @@
1
- import DOMPurify from "dompurify";
2
- import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
3
- import { customElement, property, state } from "lit/decorators.js";
4
- import { unsafeHTML } from "lit/directives/unsafe-html.js";
5
- import MyPubnub, { SimpleTextChatMessage } from "../MyPubnub";
6
- import { v4 as uuid } from "uuid";
7
- import axios from "axios";
8
- import { classMap } from "lit/directives/class-map.js";
9
- import { InputStyles } from "./actions/InputStyles";
10
- import { isMobile } from "../utils";
11
- import { LogType, sendLoggingEvent } from "../analytics";
12
- import { pubnubChatStyles } from "./pubnub-chat-styles";
13
- import "./mini-loader";
14
- import { WidgetType } from "../main/MEChat";
15
-
16
- interface WebsitePreview {
17
- title: string | null;
18
- description: string | null;
19
- image: string | null;
20
- favicon: string | null;
21
- link: string;
22
- }
23
-
24
- interface ImageToDisplay {
25
- redirectTo: string;
26
- source: string;
27
- }
28
- @customElement("pubnub-message")
29
- export class PubnubMessage extends LitElement {
30
- static styles = [
31
- InputStyles,
32
- pubnubChatStyles,
33
- css`
34
- .message-inner-body {
35
- position: relative;
36
- }
37
- .message-loader {
38
- position: absolute;
39
- bottom: -2px;
40
- right: -2px;
41
- }
42
- `,
43
- ];
44
-
45
- @property({ attribute: true })
46
- buildingSlug: string | undefined;
47
-
48
- @property({
49
- attribute: true,
50
- })
51
- message: SimpleTextChatMessage | undefined;
52
-
53
- @property({ attribute: true })
54
- myPubnub: MyPubnub | undefined;
55
-
56
- @property({ attribute: true })
57
- onMount: () => void = () => ({});
58
-
59
- @state()
60
- loadingPreviews = true;
61
-
62
- @state()
63
- parsedMessage: TemplateResult | undefined;
64
-
65
- @state()
66
- websitePreviewInfo: WebsitePreview[] = [];
67
-
68
- @state()
69
- imagesToDisplay: ImageToDisplay[] = [];
70
-
71
- @state()
72
- imageUrlError: string[] = [];
73
-
74
- @property({ type: Boolean })
75
- isLeadMessage = false;
76
-
77
- @property({ attribute: true })
78
- widgetType: WidgetType = WidgetType.Default;
79
-
80
- isMessageStillStreamingChunks(): boolean {
81
- if (!this.message) return false;
82
- const messageChunkMarkedAsDone = this.message.chunks.find(
83
- (chunk) => chunk.isDone
84
- );
85
- if (!messageChunkMarkedAsDone) return true;
86
-
87
- // We check to see if ALL the chunks have been received
88
- return this.message.chunks.length === messageChunkMarkedAsDone.order;
89
- }
90
-
91
- updated(changedProperties: PropertyValues<this>): void {
92
- this.onMount();
93
- if (!changedProperties.has("message")) return;
94
- if (!this.message) return;
95
-
96
- try {
97
- if (
98
- !this.isMessageStillStreamingChunks() &&
99
- !this.isLeadMessage &&
100
- this.invalidMarkdownText(this.message.message)
101
- ) {
102
- sendLoggingEvent({
103
- logType: LogType.error,
104
- logTitle: "INVALID_MARKDOWN",
105
- logData: {
106
- message: this.message.message,
107
- chatId: this.myPubnub?.channel,
108
- },
109
- buildingSlug: this.buildingSlug,
110
- });
111
- }
112
- } catch (error) {
113
- // eslint-disable-next-line no-console
114
- console.error("Error parsing markdown:", error);
115
- }
116
-
117
- const { hyperlinks, markedText } = this.mapAndMarkHyperLinks(
118
- this.message.message
119
- );
120
- const urlRegex = /(https?:\/\/[^\s]+)/g; // Regular expression to match URLs
121
- const loadingWebsitePreviews: Promise<WebsitePreview>[] = [];
122
- const imagesToDisplay: ImageToDisplay[] = [];
123
- this.parsedMessage = html`${markedText
124
- .trim()
125
- .split("\n")
126
- .map((line) => {
127
- const sanitizedLine = this.sanitizeMarkdownText(line);
128
- const allWords = this.preserveHTMLTags(sanitizedLine);
129
- if (!allWords) return html``;
130
- return html`${allWords.map((word) => {
131
- if (hyperlinks.find((obj) => obj.id === word)) {
132
- // EliseAI made hyperlink
133
- const link = hyperlinks.find((obj) => obj.id === word);
134
- if (!link) return;
135
- imagesToDisplay.push({
136
- redirectTo: link?.link,
137
- source: link?.link,
138
- });
139
- return html`<a
140
- class="redirect-link"
141
- href="${link?.link}"
142
- target="_blank"
143
- rel="noopener noreferrer"
144
- >${link?.hyperlink}
145
- </a>`;
146
- }
147
- if (urlRegex.test(word)) {
148
- // general url
149
- const link = this.removeTrailingPunctuation(word);
150
- loadingWebsitePreviews.push(this.getLinkData(link));
151
- return html`<a
152
- class="redirect-link"
153
- href="${link}"
154
- target="_blank"
155
- rel="noopener noreferrer"
156
- >${link}
157
- </a>`;
158
- } else {
159
- return html`${unsafeHTML(DOMPurify.sanitize(word))} `;
160
- }
161
- })}<br />`;
162
- })}`;
163
- this.imagesToDisplay = imagesToDisplay;
164
- Promise.all(loadingWebsitePreviews).then((results) => {
165
- this.websitePreviewInfo = results;
166
- });
167
- }
168
-
169
- private invalidMarkdownText(text: string): boolean {
170
- try {
171
- const markdownErrors = [
172
- /\*\*[^*\n]*\*$/, // Unclosed bold (excluding newline)
173
- /__[^_\n]*_$/, // Unclosed italic (excluding newline)
174
- /`[^`\n]*`$/, // Unclosed code (excluding newline)
175
- /\[[^\]\n]*\]$/, // Unclosed link text (excluding newline)
176
- /\[[^\]]*\]\([^)\n]*\)$/, // Unclosed link URL (excluding newline)
177
- /^(#+)\s*$/, // Header without text
178
- /(^|[^!])\[[^\]]*\]\(([^)]+)\s*\)$/, // Improperly formatted link
179
- /(?:^|\s)[*_]{1,2}(?:\s|$)/, // Improper use of bold or italic
180
- ];
181
-
182
- return markdownErrors.some((regex) => regex.test(text));
183
- } catch (error) {
184
- return false;
185
- }
186
- }
187
- private preserveHTMLTags(text: string): string[] {
188
- const tagRegex = /(<\/?[a-z][^>]*>[^<]*<\/?[a-z]*>|[^\s]+[.,?!]?|\S)/gi;
189
- const splitTags = text.match(tagRegex);
190
-
191
- return splitTags?.filter((str) => str.trim() !== "") ?? [];
192
- }
193
-
194
- private sanitizeMarkdownText(text: string): string {
195
- const toHTML = text
196
- .replace(/^### (.*$)/gim, "<h3>$1</h3>")
197
- .replace(/^## (.*$)/gim, "<h2>$1</h2>")
198
- .replace(/^# (.*$)/gim, "<h1>$1</h1>")
199
- .replace(/\*\*(.*?)\*\*/gim, "<b>$1</b>")
200
- .replace(/\*(.*?)\*/gim, "<i>$1</i>");
201
-
202
- return toHTML.trim();
203
- }
204
-
205
- private removeTrailingPunctuation(text: string): string {
206
- const punctuation = [".", ",", "!", "?", ":", ";"];
207
- if (punctuation.includes(text[text.length - 1])) {
208
- return this.removeTrailingPunctuation(text.slice(0, -1));
209
- }
210
- return text;
211
- }
212
- private mapAndMarkHyperLinks(text: string): {
213
- hyperlinks: {
214
- link: string;
215
- hyperlink: string;
216
- mark: string;
217
- id: string;
218
- }[];
219
- markedText: string;
220
- } {
221
- // Updated regex to match all formats (EliseAI, embedded links, and markdown)
222
- const regex =
223
- /<https?:\/\/[^|]+\|[^>]+>|<a href="[^"]+"(?: target="[^"]*")?>[^<]+<\/a>|\[.*?\]\([^)]*\.[^)]*\)/g;
224
-
225
- const matches = Array.from(text.matchAll(regex));
226
- const listHyperlinks: {
227
- link: string;
228
- hyperlink: string;
229
- mark: string;
230
- id: string;
231
- }[] = [];
232
-
233
- const matchesParsed = matches.map((match) => {
234
- const matchedLink = match[0];
235
- if (match.index === undefined) return;
236
- const charBefore = text[match.index - 1];
237
- const charAfter = text[match.index + matchedLink.length];
238
-
239
- // Handle for Elise Format
240
- if (matchedLink.startsWith("<https") || matchedLink.startsWith("<http")) {
241
- return {
242
- matchedLink,
243
- link: matchedLink.split("|")[0].replace("<", ""),
244
- hyperlink: matchedLink.split("|")[1].replace(">", ""),
245
- addSpaceBefore: !!(charBefore && charBefore !== " "),
246
- addSpaceAfter: !!(charAfter && charAfter !== " "),
247
- };
248
- } else if (matchedLink.startsWith("<a href=")) {
249
- // Handle for embedded links (<a>...</a>)
250
- const linkMatch = matchedLink.match(/href="([^"]+)"/);
251
- const hyperlinkMatch = matchedLink.match(/>[^<]+</);
252
- return {
253
- matchedLink,
254
- link: linkMatch ? linkMatch[1] : "",
255
- hyperlink: hyperlinkMatch ? hyperlinkMatch[0].slice(1, -1) : "",
256
- addSpaceBefore: !!(charBefore && charBefore !== " "),
257
- addSpaceAfter: !!(charAfter && charAfter !== " "),
258
- };
259
- } else {
260
- // Handle for markdown links
261
- const [hyperlinkMatch, linkMatch] = matchedLink.split("](");
262
- return {
263
- matchedLink,
264
- link: linkMatch ? linkMatch.slice(0, -1) : "",
265
- hyperlink: hyperlinkMatch ? hyperlinkMatch.slice(1) : "",
266
- addSpaceBefore: !!(charBefore && charBefore !== " "),
267
- addSpaceAfter: !!(charAfter && charAfter !== " "),
268
- };
269
- }
270
- });
271
-
272
- matchesParsed.forEach((match) => {
273
- if (!match) return;
274
-
275
- if (match.link && match.hyperlink) {
276
- const uniqueKeyMark = uuid().replace(/-/g, "");
277
- listHyperlinks.push({
278
- link: this.removeTrailingPunctuation(match.link),
279
- hyperlink: this.removeTrailingPunctuation(match.hyperlink),
280
- mark: match.matchedLink,
281
- id: uniqueKeyMark,
282
- });
283
-
284
- text = text.replace(
285
- match.matchedLink,
286
- `${match.addSpaceBefore ? " " : ""}${uniqueKeyMark}${
287
- match.addSpaceAfter ? " " : ""
288
- }`
289
- );
290
- }
291
- });
292
-
293
- return { hyperlinks: listHyperlinks, markedText: text };
294
- }
295
-
296
- private async getLinkData(url: string): Promise<WebsitePreview> {
297
- try {
298
- // Getting link data is unlikely to work unless the site has CORS enabled and/or url is on the same domain
299
- // For dev testing, can visit https://cors-anywhere.herokuapp.com/ and prefix url with it to bypass CORS
300
- const response = await axios.get(url);
301
- const html = response.data;
302
- const parser = new DOMParser(); // creates a temp dom to parse HTML
303
- const doc = parser.parseFromString(html, "text/html");
304
- if (!doc)
305
- return {
306
- title: null,
307
- description: null,
308
- image: null,
309
- favicon: null,
310
- link: url,
311
- };
312
-
313
- return {
314
- title: doc.querySelector("title")?.textContent ?? null,
315
- description:
316
- doc
317
- .querySelector('meta[name="description"]')
318
- ?.getAttribute("content") || null,
319
- image:
320
- doc
321
- .querySelector('meta[property="og:image"]')
322
- ?.getAttribute("content") || null,
323
- favicon: null, // https://meetelise.slack.com/archives/C03HAFYV2NN/p1707339577924899?thread_ts=1707317394.998999&cid=C03HAFYV2NN
324
- link: url,
325
- };
326
- } catch (error) {
327
- // eslint-disable-next-line no-console
328
- console.error("Error fetching website details:", error);
329
- return {
330
- title: null,
331
- description: null,
332
- image: null,
333
- favicon: null,
334
- link: url,
335
- };
336
- }
337
- }
338
-
339
- render(): TemplateResult {
340
- if (!this.message) return html``;
341
- return html`<div class="message-inner-body">
342
- ${this.isMessageStillStreamingChunks()
343
- ? html`<div class="message-loader"><mini-loader></mini-loader></div>`
344
- : ""}
345
- <p
346
- class=${classMap({
347
- ["message-text"]: this.widgetType !== WidgetType.Utilities,
348
- ["message-text-large"]: this.widgetType === WidgetType.Utilities,
349
- ["webchat-font__desktop"]: !isMobile(),
350
- ["webchat-font__mobile"]: isMobile(),
351
- })}
352
- >
353
- ${this.parsedMessage}
354
- </p>
355
- ${this.websitePreviewInfo.length > 0 &&
356
- this.websitePreviewInfo.some(
357
- (preview) => preview.title && (preview.image || preview.favicon)
358
- )
359
- ? html`<br />`
360
- : ""}
361
- ${this.imagesToDisplay.map((image) => {
362
- return html`<a
363
- href="${image.redirectTo}"
364
- target="_blank"
365
- rel="noopener noreferrer"
366
- ><img
367
- class=${this.imageUrlError.includes(image.source)
368
- ? "displayed-message-image-error"
369
- : "displayed-message-image"}
370
- src=${image.source}
371
- alt="displayed message image"
372
- @error=${() => {
373
- // to trigger rerender
374
- this.imageUrlError = [...this.imageUrlError, image.source];
375
- }}
376
- /></a>`;
377
- })}
378
- ${this.websitePreviewInfo.map((preview) => {
379
- if (!preview.title || !(preview.image || preview.favicon)) return;
380
- return html` <a
381
- class="redirect-link-preview"
382
- href=${preview.link}
383
- target="_blank"
384
- rel="noopener noreferrer"
385
- >
386
- <div class="website-preview">
387
- ${
388
- preview.image || preview.favicon
389
- ? html` <img
390
- src=${preview.image ?? preview.favicon}
391
- class="website-preview-image"
392
- alt="website preview image"
393
- width="100%"
394
- height="100%"
395
- />`
396
- : ""
397
- }
398
-
399
- <div class="website-preview-body">
400
- <p class=${classMap({
401
- ["message-text"]: this.widgetType !== WidgetType.Utilities,
402
- ["message-text-large"]:
403
- this.widgetType === WidgetType.Utilities,
404
- ["website-preview-title"]: true,
405
- ["webchat-font__desktop"]: !isMobile(),
406
- ["webchat-font__mobile"]: isMobile(),
407
- })}>${preview.title}</p>
408
- ${
409
- preview.description
410
- ? html`<p
411
- class=${classMap({
412
- ["message-text"]:
413
- this.widgetType !== WidgetType.Utilities,
414
- ["message-text-large"]:
415
- this.widgetType === WidgetType.Utilities,
416
- ["website-preview-description"]: true,
417
- ["webchat-font__desktop"]: !isMobile(),
418
- ["webchat-font__mobile"]: isMobile(),
419
- })}
420
- >
421
- ${preview.description}
422
- </p>`
423
- : ""
424
- }
425
- </div>
426
- </div>
427
- </a></div> `;
428
- })}
429
- </div>`;
430
- }
431
- }