@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
@@ -0,0 +1,707 @@
1
+ import { html, LitElement, TemplateResult } from "lit";
2
+ import { customElement, property, query, state } from "lit/decorators.js";
3
+ import { classMap } from "lit/directives/class-map.js";
4
+ import { styleMap } from "lit/directives/style-map.js";
5
+ import { Building } from "../fetchBuildingInfo";
6
+ import MyPubnub, {
7
+ SimpleMessageTypes,
8
+ SimpleChatMessage,
9
+ isSimpleMediaChatMessage,
10
+ isSimpleTextChatMessage,
11
+ } from "../MyPubnub";
12
+ import {
13
+ CheckboxEmpty,
14
+ HeyThereEmoji,
15
+ SendMessageIconBlack,
16
+ SendMessageIconBlackLarge,
17
+ SendMessageIconWhite,
18
+ XBlackOutlineIcon,
19
+ } from "../svgIcons";
20
+ import {
21
+ defaultBrandColor,
22
+ hexToAlmostWhite,
23
+ defaultBackgroundColor,
24
+ } from "../themes";
25
+ import { isMobile } from "../utils";
26
+ import { InputStyles } from "./actions/InputStyles";
27
+ import { healthChatStyles } from "./healthchat-styles";
28
+ import { leasingChatStyles } from "./leasing-chat-styles";
29
+ import { pubnubChatStyles } from "./pubnub-chat-styles";
30
+ import "./pubnub-message";
31
+ import "./pubnub-media";
32
+ import classNames from "classnames";
33
+ import { differenceInDays } from "date-fns";
34
+
35
+ @customElement("pubnub-chat")
36
+ export class PubnubChat extends LitElement {
37
+ static styles = [
38
+ InputStyles,
39
+ pubnubChatStyles,
40
+ leasingChatStyles,
41
+ healthChatStyles,
42
+ ];
43
+
44
+ @property({ type: Number })
45
+ private right = undefined;
46
+
47
+ @property({ type: Number })
48
+ private bottom = undefined;
49
+
50
+ @property({ type: Number })
51
+ private top = undefined;
52
+
53
+ @property({ type: Number })
54
+ private left = undefined;
55
+
56
+ @property({ attribute: true })
57
+ onMount: () => void = () => ({});
58
+
59
+ @property({ attribute: true })
60
+ channel: string | undefined;
61
+
62
+ @property({ attribute: true })
63
+ isHealthChat = false;
64
+
65
+ @property({ attribute: true })
66
+ myPubnub: MyPubnub | undefined;
67
+
68
+ @property({ attribute: true })
69
+ orgSlug: string | undefined;
70
+
71
+ @property({ attribute: true })
72
+ buildingSlug: string | undefined;
73
+
74
+ @property({ attribute: true })
75
+ building: Building | undefined;
76
+
77
+ @property({ attribute: true })
78
+ brandColor: string = defaultBrandColor;
79
+
80
+ @property({ attribute: true })
81
+ backgroundColor: string = defaultBackgroundColor;
82
+
83
+ @property({ attribute: true })
84
+ onClickExit: () => void = () => {
85
+ localStorage.setItem("isChatOpen", "false");
86
+ };
87
+
88
+ @property({ attribute: true })
89
+ requiresConsent = false;
90
+
91
+ @query("#message-input", true)
92
+ messageInput!: HTMLTextAreaElement;
93
+
94
+ @query("#conversation-body", true)
95
+ messageBody!: HTMLDivElement;
96
+
97
+ @state()
98
+ messages: SimpleChatMessage[] = [];
99
+
100
+ @state()
101
+ isLoadingMessages = false;
102
+
103
+ @state()
104
+ hasReceivedConsent = false;
105
+
106
+ @state()
107
+ privacyPolicyUrl = "http://bit.ly/me_privacy_policy";
108
+
109
+ @state()
110
+ websitePreviewMapping: {
111
+ [messageId: string]: {
112
+ title: string | null;
113
+ description: string | null;
114
+ image: string | null;
115
+ favicon: string | null;
116
+ isLoading: boolean;
117
+ }[];
118
+ } = {};
119
+
120
+ get consentKey(): string {
121
+ return `${this.orgSlug}Consent`;
122
+ }
123
+
124
+ sendMessage = async (message: string): Promise<void> => {
125
+ this.messageInput.value = "";
126
+ this.autoResizeMessageInput();
127
+
128
+ // The first message triggers a channel creation which can take a few seconds,
129
+ // so we immediately add the message to the UI to avoid a delay.
130
+ if (this.messages.length === 0) {
131
+ this.messages = [
132
+ {
133
+ timestamp: 0,
134
+ message,
135
+ isLeadMessage: true,
136
+ chunks: [{ text: message, order: 0, isDone: true }],
137
+ type: SimpleMessageTypes.text,
138
+ },
139
+ ];
140
+ }
141
+ await this.myPubnub?.sendMessage(message);
142
+ };
143
+ firstUpdated(): void {
144
+ this.messages = this.myPubnub?.simpleChatMessages || [];
145
+ this.myPubnub?.addChatListener(
146
+ (response: { messages: SimpleChatMessage[]; isLoading: boolean }) => {
147
+ this.messages = response.messages;
148
+ this.isLoadingMessages = response.isLoading;
149
+ }
150
+ );
151
+ this.onMount();
152
+
153
+ const rawConsentData = localStorage.getItem(this.consentKey);
154
+ if (!rawConsentData) {
155
+ this.hasReceivedConsent = false;
156
+ return;
157
+ }
158
+ const parsedConsentData = JSON.parse(rawConsentData);
159
+ const { timestamp, consentId } = parsedConsentData;
160
+ const ageInDays = differenceInDays(new Date(), new Date(timestamp));
161
+ const isConsentValid = ageInDays < 7;
162
+ const isConsentIdCurrent = consentId === CURRENT_CONSENT_ID;
163
+ if (isConsentValid && isConsentIdCurrent) {
164
+ this.hasReceivedConsent = true;
165
+ } else {
166
+ this.hasReceivedConsent = false;
167
+ localStorage.removeItem(this.consentKey);
168
+ }
169
+ }
170
+
171
+ scrollToChatBottom = (): void => {
172
+ this.messageBody.scrollTo({
173
+ top: this.messageBody.scrollHeight - this.messageBody.clientHeight,
174
+ behavior: "smooth",
175
+ });
176
+ };
177
+
178
+ async updated(): Promise<void> {
179
+ this.scrollToChatBottom();
180
+ try {
181
+ const modal = document.getElementById("#healthchat-container");
182
+ if (!modal) return;
183
+ modal.focus();
184
+ } catch (e) {
185
+ // eslint-disable-next-line no-console
186
+ console.error(e);
187
+ }
188
+ }
189
+
190
+ autoResizeMessageInput = (): void => {
191
+ this.messageInput.style.height = "auto";
192
+ this.messageInput.style.height = this.messageInput.scrollHeight + "px";
193
+ };
194
+
195
+ needsConsent = (): boolean => {
196
+ return this.requiresConsent && !this.hasReceivedConsent;
197
+ };
198
+
199
+ render(): TemplateResult {
200
+ if (!this.buildingSlug) {
201
+ return html``; // error should be here
202
+ }
203
+
204
+ let styles = {};
205
+ if (isMobile()) {
206
+ styles = {
207
+ top: undefined,
208
+ bottom: 0,
209
+ left: undefined,
210
+ right: 0,
211
+ };
212
+ } else {
213
+ styles = {
214
+ top:
215
+ this.top !== undefined && !isNaN(this.top)
216
+ ? `${this.top}px`
217
+ : undefined,
218
+ bottom:
219
+ this.bottom !== undefined && !isNaN(this.bottom)
220
+ ? `${this.bottom}px`
221
+ : "130px",
222
+ left:
223
+ this.left !== undefined && !isNaN(this.left)
224
+ ? `${this.left}px`
225
+ : undefined,
226
+ right:
227
+ this.right !== undefined && !isNaN(this.right)
228
+ ? `${this.right}px`
229
+ : "18px",
230
+ };
231
+ }
232
+
233
+ if (this.isHealthChat) {
234
+ return html`
235
+ <div
236
+ id="healthchat-container"
237
+ class=${classMap({
238
+ ["pubnub-container__mobile"]: isMobile(),
239
+ ["healthchat-container__desktop"]: !isMobile(),
240
+ })}
241
+ style=${styleMap(styles)}
242
+ >
243
+ <div id="healthchat-header">
244
+ ${this.buildingSlug === "6a9e65e5-9699-4c96-af75-1741d0df79aa"
245
+ ? html` <div>
246
+ <div id="header-text">Premier Dematology</div>
247
+ <div id="healthchat-header-subtext">
248
+ Recorded by Forefront Dermatology and our vendors.
249
+ </div>
250
+ </div>`
251
+ : html``}
252
+
253
+ <button id="exit-chat-bttn" @click=${this.onClickExit}>
254
+ ${XBlackOutlineIcon}
255
+ </button>
256
+ </div>
257
+ <div
258
+ class=${classMap({
259
+ ["hidden"]: !this.needsConsent(),
260
+ ["legal-confirmation-container"]: true,
261
+ })}
262
+ >
263
+ ${getConsentPreChatDisclaimer(
264
+ this.orgSlug ?? null,
265
+ this.privacyPolicyUrl,
266
+ this.consentKey,
267
+ (hasConsent: boolean) => {
268
+ this.hasReceivedConsent = hasConsent;
269
+ }
270
+ )}
271
+ </div>
272
+ <div
273
+ id="conversation-body"
274
+ class=${classMap({
275
+ ["hidden"]: this.needsConsent(),
276
+ ["healthcare-conversation-body-backdrop"]: true,
277
+ })}
278
+ >
279
+ <ul
280
+ id="message-thread-list"
281
+ class=${classMap({
282
+ ["hidden"]: this.needsConsent(),
283
+ })}
284
+ >
285
+ <li class="healthcare-disclaimer-message">
286
+ <p class="healthcare-disclaimer-inner">
287
+ Hi! I am a third-party bot. Your messages with me are recorded
288
+ by Forefront Dermatology and our vendors. By replying, you
289
+ consent to
290
+ <a
291
+ href="https://www.eliseai.com/privacy/healthcare"
292
+ target="_blank"
293
+ rel="noopener noreferrer"
294
+ >
295
+ this privacy policy</a
296
+ >
297
+ and to being contacted by a bot.
298
+ </p>
299
+ </li>
300
+ <li class="message-container ai-message">
301
+ <p
302
+ class=${classMap({
303
+ ["message-text"]: true,
304
+ ["webchat-font__desktop"]: !isMobile(),
305
+ ["webchat-font__mobile"]: isMobile(),
306
+ })}
307
+ >
308
+ Hi I'm Elise. If this is a medical emergency, please call 911.
309
+ How can I assist you today?
310
+ </p>
311
+ </li>
312
+ ${this.messages.map((message) => {
313
+ return html`
314
+ <li
315
+ class=${message.isLeadMessage
316
+ ? "message-container lead-message"
317
+ : "message-container ai-message"}
318
+ key=${message.timestamp}
319
+ >
320
+ ${isSimpleMediaChatMessage(message)
321
+ ? html` <pubnub-media
322
+ .message=${message}
323
+ .myPubnub=${this.myPubnub}
324
+ .onMount=${() => this.scrollToChatBottom()}
325
+ >
326
+ </pubnub-media>`
327
+ : ""}
328
+ ${isSimpleTextChatMessage(message)
329
+ ? html` <pubnub-message
330
+ .message=${message}
331
+ .myPubnub=${this.myPubnub}
332
+ .onMount=${() => this.scrollToChatBottom()}
333
+ .isLeadMessage=${message.isLeadMessage}
334
+ .buildingSlug=${this.buildingSlug}
335
+ >
336
+ </pubnub-message>`
337
+ : ""}
338
+ </li>
339
+ `;
340
+ })}
341
+ ${this.isLoadingMessages
342
+ ? html`
343
+ <li
344
+ id="loading-message"
345
+ class="message-container ai-message"
346
+ >
347
+ <div class="loading-dot dot-1"></div>
348
+ <div class="loading-dot dot-2"></div>
349
+ <div class="loading-dot dot-3"></div>
350
+ </li>
351
+ `
352
+ : ""}
353
+ </ul>
354
+ </div>
355
+
356
+ <div
357
+ id="healthcare-footer"
358
+ class=${classMap({
359
+ ["hidden"]: this.needsConsent(),
360
+ })}
361
+ >
362
+ <div id="healthcare-inner-footer">
363
+ <textarea
364
+ id="message-input"
365
+ class=${classMap({
366
+ ["webchat-font__desktop"]: !isMobile(),
367
+ ["webchat-font__mobile"]: isMobile(),
368
+ })}
369
+ placeholder="Ask a Question..."
370
+ @keydown=${(e: KeyboardEvent) => {
371
+ if (e.key === "Enter") {
372
+ e.preventDefault();
373
+ this.sendMessage(this.messageInput.value);
374
+ }
375
+ }}
376
+ @input=${() => this.autoResizeMessageInput()}
377
+ rows="1"
378
+ tabindex="0"
379
+ ></textarea>
380
+ <button
381
+ id="healthcare-send-message-bttn"
382
+ class=${classMap({
383
+ ["health-bttn-allow-access"]: isMobile(),
384
+ })}
385
+ @click=${() => this.sendMessage(this.messageInput.value)}
386
+ >
387
+ ${isMobile() ? SendMessageIconBlackLarge : SendMessageIconBlack}
388
+ </button>
389
+ </div>
390
+ </div>
391
+ </div>
392
+ `;
393
+ }
394
+
395
+ if (!this.building) {
396
+ return html``;
397
+ }
398
+
399
+ const orgId = this.building.orgId;
400
+ return html`
401
+ <div
402
+ id="pubnub-chat-container"
403
+ class=${classMap({
404
+ ["pubnub-container__mobile"]: isMobile(),
405
+ ["pubnub-container__desktop"]: !isMobile(),
406
+ })}
407
+ style=${styleMap(styles)}
408
+ >
409
+ <div
410
+ id="leasing-header"
411
+ style=${styleMap({
412
+ background:
413
+ this.brandColor !== defaultBrandColor
414
+ ? hexToAlmostWhite(this.brandColor, 0.6)
415
+ : undefined,
416
+ })}
417
+ >
418
+ <div id="header-text">${this.building.name}</div>
419
+ <button id="exit-chat-bttn" @click=${this.onClickExit}>
420
+ ${XBlackOutlineIcon}
421
+ </button>
422
+ </div>
423
+ <div
424
+ class=${classMap({
425
+ ["hidden"]: !this.needsConsent(),
426
+ ["legal-confirmation-container"]: true,
427
+ })}
428
+ >
429
+ ${getConsentPreChatDisclaimer(
430
+ this.orgSlug ?? null,
431
+ this.privacyPolicyUrl,
432
+ this.consentKey,
433
+ (hasConsent: boolean) => {
434
+ this.hasReceivedConsent = hasConsent;
435
+ }
436
+ )}
437
+ </div>
438
+ <div
439
+ id="conversation-body"
440
+ style=${styleMap({
441
+ background:
442
+ this.building.orgId === 444
443
+ ? "rgba(229, 229, 229, 1);"
444
+ : undefined,
445
+ })}
446
+ class=${classMap({
447
+ ["hidden"]: this.needsConsent(),
448
+ ["leasing-conversation-body-backdrop"]: true,
449
+ })}
450
+ >
451
+ <ul
452
+ id="message-thread-list"
453
+ class=${classMap({
454
+ ["hidden"]: this.needsConsent(),
455
+ })}
456
+ >
457
+ ${getChatDisclaimer(this.orgSlug ?? "")}
458
+ ${this.building.welcomeMessage
459
+ ? html` <li
460
+ class=${classMap({
461
+ "message-container": true,
462
+ "ai-message": true,
463
+ "with-box-shadow": orgId === 444,
464
+ })}
465
+ >
466
+ <p
467
+ class=${classMap({
468
+ ["message-text"]: true,
469
+ ["webchat-font__desktop"]: !isMobile(),
470
+ ["webchat-font__mobile"]: isMobile(),
471
+ })}
472
+ >
473
+ ${this.building.welcomeMessage}
474
+ </p>
475
+ </li>`
476
+ : ""}
477
+ ${this.messages.map((message) => {
478
+ return html`
479
+ <li
480
+ class=${classNames("message-container", {
481
+ "lead-message": message.isLeadMessage,
482
+ "ai-message": !message.isLeadMessage,
483
+ "with-box-shadow": orgId === 444,
484
+ })}
485
+ key=${message.timestamp}
486
+ >
487
+ ${isSimpleMediaChatMessage(message)
488
+ ? html` <pubnub-media
489
+ .message=${message}
490
+ .myPubnub=${this.myPubnub}
491
+ .onMount=${() => this.scrollToChatBottom()}
492
+ >
493
+ </pubnub-media>`
494
+ : ""}
495
+ ${isSimpleTextChatMessage(message)
496
+ ? html` <pubnub-message
497
+ .message=${message}
498
+ .myPubnub=${this.myPubnub}
499
+ .onMount=${() => this.scrollToChatBottom()}
500
+ .isLeadMessage=${message.isLeadMessage}
501
+ .buildingSlug=${this.buildingSlug}
502
+ >
503
+ </pubnub-message>`
504
+ : ""}
505
+ </li>
506
+ `;
507
+ })}
508
+ ${this.isLoadingMessages
509
+ ? html`
510
+ <li id="loading-message" class="message-container ai-message">
511
+ <div class="loading-dot dot-1"></div>
512
+ <div class="loading-dot dot-2"></div>
513
+ <div class="loading-dot dot-3"></div>
514
+ </li>
515
+ `
516
+ : ""}
517
+ </ul>
518
+ </div>
519
+ <div
520
+ id="footer"
521
+ class=${classMap({
522
+ ["hidden"]: this.needsConsent(),
523
+ })}
524
+ >
525
+ <textarea
526
+ id="message-input"
527
+ class=${classMap({
528
+ ["webchat-font__desktop"]: !isMobile(),
529
+ ["webchat-font__mobile"]: isMobile(),
530
+ })}
531
+ placeholder="Ask a question..."
532
+ @keydown=${(e: KeyboardEvent) => {
533
+ if (
534
+ e.key === "Enter" &&
535
+ !this.myPubnub?.isCurrentlyStreamingMessage
536
+ ) {
537
+ e.preventDefault();
538
+ this.sendMessage(this.messageInput.value);
539
+ }
540
+ }}
541
+ @input=${() => this.autoResizeMessageInput()}
542
+ rows="1"
543
+ tabindex="0"
544
+ ></textarea>
545
+ <button
546
+ tabindex="0"
547
+ id="send-message-bttn"
548
+ @click=${() => this.sendMessage(this.messageInput.value)}
549
+ ?disabled=${this.myPubnub?.isCurrentlyStreamingMessage}
550
+ >
551
+ ${SendMessageIconWhite}
552
+ </button>
553
+ </div>
554
+ </div>
555
+ `;
556
+ }
557
+ }
558
+
559
+ export const CURRENT_CONSENT_ID = "currentConsentId";
560
+
561
+ const getChatDisclaimer = (orgSlug: string) => {
562
+ if (orgSlug === "avb") {
563
+ return html`
564
+ <li class="message-container disclaimer-message">
565
+ <p class="disclaimer-inner">
566
+ Chats may be recorded by us and our vendors.
567
+ </p>
568
+ </li>
569
+ `;
570
+ }
571
+ return html`<li class="message-container disclaimer-message">
572
+ <p class="disclaimer-inner">
573
+ By interacting with this system, you consent to
574
+ <a
575
+ href="http://bit.ly/me_privacy_policy"
576
+ target="_blank"
577
+ rel="noopener noreferrer"
578
+ >
579
+ this privacy policy</a
580
+ >, including being contacted by AI or a human & having your conversation
581
+ recorded by a third party.
582
+ </p>
583
+ </li>`;
584
+ };
585
+
586
+ const getConsentPreChatDisclaimer = (
587
+ orgSlug: string | null,
588
+ privacyPolicyUrl: string,
589
+ consentKey: string,
590
+ changeConsent: (hasConsent: boolean) => void
591
+ ): TemplateResult => {
592
+ if (orgSlug === "avb" && !localStorage.getItem(consentKey ?? "")) {
593
+ return html`
594
+ <div class="legal-confirmation-inner-container">
595
+ <div>${HeyThereEmoji}</div>
596
+ <div>
597
+ <span style="font-weight: 600">Confirm to continue</span>
598
+ <p>
599
+ By using this feature you accept our
600
+ <a
601
+ href="https://www.avaloncommunities.com/terms-of-use"
602
+ target="_blank"
603
+ rel="noopener noreferrer"
604
+ class="privacy-policy-link"
605
+ >Terms</a
606
+ >,
607
+ <a
608
+ href="https://www.avaloncommunities.com/privacy-policy"
609
+ target="_blank"
610
+ rel="noopener noreferrer"
611
+ class="privacy-policy-link"
612
+ >Privacy Policy</a
613
+ >,
614
+ <a
615
+ href="https://www.avaloncommunities.com/us-state-privacy-notice"
616
+ target="_blank"
617
+ rel="noopener noreferrer"
618
+ class="privacy-policy-link"
619
+ >U.S. State Privacy Notice</a
620
+ >, and that chats may use automated or AI responses from a bot and
621
+ may be recorded by us and our vendors.
622
+ </p>
623
+ </div>
624
+
625
+ <button
626
+ class="agreeButton"
627
+ @click=${() => {
628
+ changeConsent(true);
629
+ const consentData = {
630
+ consentGiven: true,
631
+ timestamp: new Date().getTime(),
632
+ consentId: CURRENT_CONSENT_ID,
633
+ };
634
+ localStorage.setItem(consentKey ?? "", JSON.stringify(consentData));
635
+ }}
636
+ >
637
+ I agree
638
+ </button>
639
+ </div>
640
+ `;
641
+ }
642
+ if (orgSlug === "mill-creek") {
643
+ return html`<div class="legal-confirmation-inner-container">
644
+ <div>${HeyThereEmoji}</div>
645
+ <div>
646
+ <span style="font-weight: 600">Confirm to continue</span>
647
+ <p>
648
+ Hello! I’m your virtual assistant, Milly, and I am here to help you
649
+ today. Before I can answer any questions, it is important that you
650
+ know I am a third-party bot, and I will be collecting our
651
+ communications and other information you provide, consistent with our
652
+ privacy policy.
653
+ </p>
654
+ <div class="confirmation-with-checkbox">
655
+ <div
656
+ class="checkbox"
657
+ @click=${() => {
658
+ changeConsent(true);
659
+ }}
660
+ >
661
+ ${CheckboxEmpty}
662
+ </div>
663
+ <p>
664
+ I agree to the
665
+ <a
666
+ href=${privacyPolicyUrl}
667
+ target="_blank"
668
+ rel="noopener noreferrer"
669
+ class="privacy-policy-link"
670
+ >
671
+ privacy policy</a
672
+ >
673
+ and terms and conditions, Let’s go!
674
+ </p>
675
+ </div>
676
+ </div>
677
+ </div>`;
678
+ }
679
+ return html` <div class="legal-confirmation-inner-container">
680
+ <div>${HeyThereEmoji}</div>
681
+ <div>
682
+ <span style="font-weight: 600">Confirm to continue</span>
683
+ <p>
684
+ Hello, before I can answer questions for you, it’s important that I let
685
+ you know that I am a third-party AI Assistant that will collect our
686
+ conversation and other information you provide, consistent with our
687
+ <a
688
+ href=${privacyPolicyUrl}
689
+ target="_blank"
690
+ rel="noopener noreferrer"
691
+ class="privacy-policy-link"
692
+ >
693
+ privacy policy</a
694
+ >.
695
+ </p>
696
+ </div>
697
+
698
+ <button
699
+ class="agreeButton"
700
+ @click=${() => {
701
+ changeConsent(true);
702
+ }}
703
+ >
704
+ I agree
705
+ </button>
706
+ </div>`;
707
+ };