@meetelise/chat 1.20.63 → 1.20.65

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.
@@ -1,641 +0,0 @@
1
- import { html, LitElement, TemplateResult } from "lit";
2
- import { customElement, property, state } from "lit/decorators.js";
3
- import { createRef, ref, Ref } from "lit/directives/ref.js";
4
- import { glowBackgroundMp4 } from "../assetUrls";
5
- import { launcherStyles } from "./launcherStyles";
6
- import { EmailUsWindow, installEmailUsWindow } from "./actions/email-us-window";
7
- import { installTextUsWindow, TextUsWindow } from "./actions/text-us-window";
8
- import { StyleInfo, styleMap } from "lit/directives/style-map.js";
9
- import { classMap } from "lit/directives/class-map.js";
10
- import { installCallUsWindow } from "./actions/call-us-window";
11
- import { getRegisteredPhoneNumbers } from "../getRegisteredPhoneNumbers";
12
- import { TourScheduler } from "./Scheduler/tour-scheduler";
13
- import { LabeledOption, UnitV2 } from "../fetchBuildingInfo";
14
- import { abTestTypes } from "../fetchBuildingABTestType";
15
- import {
16
- FilledChatIcon,
17
- FilledEmailIcon,
18
- FilledPhoneIcon,
19
- FilledTourIcon,
20
- ChevronIconWhite,
21
- HeyThereEmoji,
22
- EmailBlackStrokeIcon,
23
- PhoneBlackStrokeIcon,
24
- ChatWhiteStrokeIcon,
25
- EmailWhiteStrokeIcon,
26
- TabletWhiteStrokeIcon,
27
- ChatBlueBttnIcon,
28
- PhoneWhiteStrokeIcon,
29
- ChevronIconBlack,
30
- } from "../svgIcons";
31
-
32
- @customElement("meetelise-launcher")
33
- export class Launcher extends LitElement {
34
- static styles = launcherStyles;
35
-
36
- @property({ type: Boolean })
37
- isMobile = false;
38
-
39
- @property({ type: Boolean })
40
- isMinimized = false;
41
-
42
- @property({ type: Boolean })
43
- isFirstMount = false;
44
-
45
- @property()
46
- backgroundColor = "rgba(255, 255, 255, 0.75)";
47
-
48
- @property()
49
- textColor = "#202020";
50
-
51
- @property({ type: Boolean })
52
- isMini = true;
53
- @property({ attribute: false })
54
- autoOpenChatWidget = false;
55
-
56
- @property()
57
- phoneNumber = "";
58
- @property({ attribute: true })
59
- chatId = "";
60
- @property({ attribute: true })
61
- chatCallUsHeader = "";
62
- @property({ attribute: false })
63
- buildingId = 0;
64
- @property({ attribute: true })
65
- buildingSlug = "";
66
- @property({ attribute: true })
67
- orgSlug = "";
68
- @property({ attribute: true })
69
- sgtUrl = "";
70
- @property({ attribute: true })
71
- buildingABTestType = "";
72
- @property({ attribute: true })
73
- featureFlagShowDropdown = "";
74
- @property({ attribute: false })
75
- leadSources: string[] = [];
76
- @property({ attribute: true })
77
- currentLeadSource = "";
78
- @property({ attribute: true })
79
- escortedToursLink = "";
80
- @property({ attribute: true })
81
- virtualToursLink = "";
82
- @property({ type: Boolean })
83
- hasCallUsEnabled = false;
84
- @property({ type: Boolean })
85
- hasChatEnabled = false;
86
- @property({ type: Boolean })
87
- hasEmailEnabled = false;
88
- @property({ type: Boolean })
89
- hasSSTEnabled = false;
90
- @property({ type: Boolean })
91
- hasTextUsEnabled = true;
92
- @property({ attribute: false })
93
- layoutOptions: string[] = [];
94
- @property({ attribute: false })
95
- unitOptions: UnitV2[] = [];
96
- @property({ attribute: false })
97
- tourTypeOptions: LabeledOption[] = [];
98
- @property({ attribute: false })
99
- onChatTapped: () => void = () => {
100
- return;
101
- };
102
- @property({ attribute: false })
103
- launcherStyles: StyleInfo = {};
104
-
105
- @state()
106
- isEmailWindowOpen = false;
107
- @state()
108
- isCallUsWindowOpen = false;
109
- @state()
110
- isSSTWindowOpen = false;
111
- @state()
112
- isTextUsWindowOpen = false;
113
-
114
- getNumCallToActions = (): number => {
115
- return [
116
- this.hasEmailEnabled,
117
- !!this.phoneNumber && this.hasCallUsEnabled,
118
- this.hasSSTEnabled,
119
- this.hasTextUsEnabled,
120
- ].filter((v) => v).length;
121
- };
122
-
123
- emailUsWindowRef: Ref<EmailUsWindow> = createRef();
124
- textUsWindowRef: Ref<TextUsWindow> = createRef();
125
- tourSchedulerRef: Ref<TourScheduler> = createRef();
126
-
127
- updated = async (): Promise<void> => {
128
- this.attachOnClickToEmailUsWindow();
129
- this.attachOnClickToTextUsWindow();
130
- this.attachOnClickToSSTWindow();
131
- if (this.buildingId) {
132
- const registeredPhoneNumbers = await getRegisteredPhoneNumbers(
133
- this.buildingId
134
- );
135
- this.hasTextUsEnabled =
136
- registeredPhoneNumbers.length > 0 &&
137
- this.hasTextUsEnabled &&
138
- this.buildingId !== 4895;
139
- // TODO: replace this with the real API call once the endpoint exists
140
- const schedulingIsEnabled = await (async function putApiCallHere(
141
- buildingId: number
142
- ) {
143
- return !!buildingId;
144
- })(this.buildingId);
145
- if (schedulingIsEnabled && this.hasSSTEnabled) {
146
- this.hasSSTEnabled = true;
147
- }
148
- }
149
- };
150
-
151
- attachOnClickToEmailUsWindow = (): void => {
152
- const emailUsWindowRef = this.emailUsWindowRef.value;
153
- if (!emailUsWindowRef) {
154
- return;
155
- }
156
- emailUsWindowRef.onCloseClicked = this.onCloseEmailWindow;
157
- };
158
-
159
- attachOnClickToTextUsWindow = (): void => {
160
- const textUsWindowRef = this.textUsWindowRef.value;
161
- if (!textUsWindowRef) {
162
- return;
163
- }
164
- textUsWindowRef.onCloseClicked = this.onCloseTextUsWindow;
165
- };
166
-
167
- attachOnClickToSSTWindow = (): void => {
168
- const sstWindowRef = this.tourSchedulerRef.value;
169
- if (!sstWindowRef) {
170
- return;
171
- }
172
- sstWindowRef.onCloseClicked = this.onCloseSSTWindow;
173
- };
174
-
175
- onClickEmailOption = (e: MouseEvent): void => {
176
- e.preventDefault();
177
- e.stopPropagation();
178
-
179
- this.isEmailWindowOpen = true;
180
- };
181
-
182
- onCloseEmailWindow = (): void => {
183
- this.isEmailWindowOpen = false;
184
- };
185
-
186
- renderEmailOption = (): TemplateResult => {
187
- const text = this.getNumCallToActions() > 2 ? "Email" : "Email us";
188
- return html`
189
- <div
190
- @click=${this.onClickEmailOption}
191
- class="launcher__call-to-action-option"
192
- >
193
- ${text}
194
- </div>
195
- `;
196
- };
197
-
198
- onClickPhoneOption = (e: MouseEvent): void => {
199
- e.preventDefault();
200
- e.stopPropagation();
201
- this.isCallUsWindowOpen = true;
202
- };
203
-
204
- onClosePhoneWindow = (): void => {
205
- this.isCallUsWindowOpen = false;
206
- };
207
-
208
- renderCallUsOption = (): TemplateResult => {
209
- const text = this.getNumCallToActions() > 2 ? "Phone" : "Hours/Phone";
210
- return html` <div class="launcher__call-to-action-option">${text}</div> `;
211
- };
212
-
213
- onClickSSTOption = (e: MouseEvent): void => {
214
- e.preventDefault();
215
- e.stopPropagation();
216
- this.isSSTWindowOpen = true;
217
- };
218
-
219
- onCloseSSTWindow = (): void => {
220
- this.isSSTWindowOpen = false;
221
- };
222
-
223
- renderSSTOption = (): TemplateResult => {
224
- const text = this.getNumCallToActions() > 2 ? "Book" : "Book a tour";
225
- return html`
226
- <div
227
- class="launcher__call-to-action-option"
228
- @click=${this.onClickSSTOption}
229
- >
230
- ${text}
231
- </div>
232
- `;
233
- };
234
-
235
- onClickTextUsOption = (e: MouseEvent): void => {
236
- e.preventDefault();
237
- e.stopPropagation();
238
- this.isTextUsWindowOpen = true;
239
- };
240
-
241
- onCloseTextUsWindow = (): void => {
242
- this.isTextUsWindowOpen = false;
243
- };
244
-
245
- onClickMinimize = (e: MouseEvent): void => {
246
- e.preventDefault();
247
- e.stopPropagation();
248
- this.isMinimized = !this.isMinimized;
249
- };
250
-
251
- renderTextUsOption = (): TemplateResult => {
252
- return html`
253
- <div
254
- @click=${this.onClickTextUsOption}
255
- class="launcher__call-to-action-option"
256
- >
257
- Text us
258
- </div>
259
- `;
260
- };
261
-
262
- renderCallToActions = (): TemplateResult => {
263
- if (this.getNumCallToActions() === 0) {
264
- return html``;
265
- }
266
-
267
- return html`
268
- <div class="launcher__call-to-actions-wrapper">
269
- ${this.hasEmailEnabled ? this.renderEmailOption() : ""}
270
- ${this.phoneNumber && this.hasCallUsEnabled
271
- ? this.renderCallUsOption()
272
- : ""}
273
- ${this.hasTextUsEnabled ? this.renderTextUsOption() : ""}
274
- ${this.hasSSTEnabled ? this.renderSSTOption() : ""}
275
- </div>
276
- `;
277
- };
278
-
279
- isCallToActionWindowOpen = (): boolean => {
280
- return (
281
- [
282
- this.isEmailWindowOpen,
283
- this.isCallUsWindowOpen,
284
- this.isSSTWindowOpen,
285
- this.isTextUsWindowOpen,
286
- ].filter((v) => v).length === 1
287
- );
288
- };
289
-
290
- renderMiniOption = (
291
- content: TemplateResult,
292
- onClick?: (e: MouseEvent) => void,
293
- isSecondaryAction?: boolean
294
- ): TemplateResult => {
295
- return html`
296
- <div class="launcher__mini-option-wrapper">
297
- <div
298
- @click=${onClick}
299
- class=${classMap({
300
- ["launcher__mini-option"]: true,
301
- ["launcher__secondary-option"]: !!isSecondaryAction,
302
- })}
303
- >
304
- ${content}
305
- </div>
306
- </div>
307
- `;
308
- };
309
- renderPillVertical = (
310
- content: TemplateResult,
311
- onClick: (e: MouseEvent) => void
312
- ): TemplateResult => {
313
- return html`
314
- <div @click=${onClick} class="inner-pill-wrapper">${content}</div>
315
- `;
316
- };
317
-
318
- renderActionPills = (): TemplateResult => {
319
- if (this.isMobile || this.isMinimized) {
320
- return html`<div class="typeMobile-list">
321
- ${this.isMobile
322
- ? ""
323
- : html` <button @click=${this.onClickMinimize} class="minimize-bttn">
324
- <div class="chevron-up">${ChevronIconBlack}</div>
325
- </button>`}
326
- <ul>
327
- <li @click=${this.onChatTapped} class="typeMobile-bttn">
328
- <div class="typeMobile-inner">
329
- <div class="typeMobile-icon">${ChatWhiteStrokeIcon}</div>
330
- </div>
331
- </li>
332
- <li @click=${this.onClickEmailOption} class="typeMobile-bttn">
333
- <div class="typeMobile-inner">
334
- <div class="typeMobile-icon">${EmailWhiteStrokeIcon}</div>
335
- </div>
336
- </li>
337
- <li @click=${this.onClickPhoneOption} class="typeMobile-bttn">
338
- <div class="typeMobile-inner">
339
- <div class="typeMobile-icon">${PhoneWhiteStrokeIcon}</div>
340
- </div>
341
- </li>
342
- </ul>
343
- </div>`;
344
- }
345
-
346
- if (this.buildingABTestType === abTestTypes.ConceptBlueBlack) {
347
- return html` <div class="type-gradient__list">
348
- <button @click=${this.onClickMinimize} class="minimize-bttn">
349
- <div class="chevron-down">${ChevronIconBlack}</div>
350
- </button>
351
- ${this.hasChatEnabled
352
- ? html`
353
- <div
354
- class="type-gradient__top-container"
355
- @click=${this.onChatTapped}
356
- >
357
- <video class="glowBackground" autoplay loop muted playsinline>
358
- <source src="${glowBackgroundMp4}" type="video/mp4" />
359
- </video>
360
- <div class="type-gradient__scroll-info">
361
- ${ChatWhiteStrokeIcon}
362
- <div class="type-gradient__chat-container">
363
- <div class="type-gradient__chat-header">
364
- <span class="title-bold">Chat</span> with us
365
- </div>
366
- ${ChevronIconWhite}
367
- </div>
368
- <ul class="type-gradient__description">
369
- <li>our apartments</li>
370
- <li>unit availability</li>
371
- <li>tour bookings</li>
372
- <li>our amenities</li>
373
- <li>neighborhood</li>
374
- </ul>
375
- </div>
376
- </div>
377
- `
378
- : ""}
379
- ${this.hasEmailEnabled
380
- ? html` <div class="type-gradient__email type-gradient__bottom-tab" @click=${this.onClickEmailOption}>
381
- <div class="type-gradient__icon">${EmailWhiteStrokeIcon}</div>
382
- <div class="type-gradient__inner-txt">
383
- <span class="title-bold">Email</span> an agent
384
- </div>
385
- <div class="type-gradient__icon">${ChevronIconWhite}</div>
386
- </div>
387
- </div>`
388
- : ""}
389
- ${this.phoneNumber && this.hasCallUsEnabled
390
- ? html`
391
- <div class="type-gradient__contact type-gradient__bottom-tab" @click=${
392
- this.onClickPhoneOption
393
- }>
394
- <div class="type-gradient__icon">${TabletWhiteStrokeIcon}</div>
395
- <div class="type-gradient__inner-txt">
396
- <span class="title-bold">Call</span>
397
- ${
398
- this.hasTextUsEnabled
399
- ? html`or <span class="title-bold">text</span> us`
400
- : "us"
401
- }
402
- </div>
403
- <div class="type-gradient__icon">${ChevronIconWhite}</div>
404
- </div>
405
- </div>
406
- `
407
- : ""}
408
- </div>`;
409
- }
410
-
411
- if (this.buildingABTestType === abTestTypes.ConceptBlueWhite) {
412
- return html`
413
-
414
- <div class="type-hey__list">
415
- <button @click=${this.onClickMinimize} class="minimize-bttn">
416
- <div class="chevron-down">${ChevronIconBlack}</div>
417
- </button>
418
- <div class="type-hey__top-section">
419
- <div class="type-hey__ai-topic">
420
- <p>AI Assistant</p>
421
- <div class="type-hey__ai-topic-notch"></div>
422
- </div>
423
- <div class="type-hey__greeting">
424
- <h1>Hey there!</h1>
425
- <div>${HeyThereEmoji}</div>
426
- </div>
427
- ${
428
- this.hasChatEnabled
429
- ? html`
430
- <div class="type-hey__ask-prompt" @click=${this.onChatTapped}>
431
- <div class="type-hey__ask-prompt-inner">
432
- <div class="type-hey__ask-start">
433
- <h2>Ask me about</h2>
434
- <div class="scroll-container">
435
- <ul>
436
- <li>booking a tour</li>
437
- <li>our pet policy</li>
438
- <li>our amenities</li>
439
- <li>our availability</li>
440
- </ul>
441
- </div>
442
- </div>
443
- <div>${ChevronIconWhite}</div>
444
- </div>
445
- </div>
446
- </div>
447
- `
448
- : ""
449
- }
450
- </div>
451
-
452
- <div class="type-hey__bottom-section">
453
- ${
454
- this.hasEmailEnabled
455
- ? html` <div class="type-hey__email" @click=${this.onClickEmailOption}>
456
- <div class="type-hey__icon">${EmailBlackStrokeIcon}</div>
457
- <div>
458
- <span class="title-bold">Email</span> an agent
459
- </div>
460
- <div class="type-gradient__icon">${ChevronIconWhite}</div>
461
- </div>
462
- </div>`
463
- : ""
464
- }
465
- ${
466
- this.phoneNumber && this.hasCallUsEnabled
467
- ? html`
468
- <div class="type-hey__contact" @click=${this.onClickPhoneOption}>
469
- <div class="type-hey__icon">${PhoneBlackStrokeIcon}</div>
470
- <div>
471
- <span class="title-bold">Call</span>
472
- ${
473
- this.hasTextUsEnabled
474
- ? html`or <span class="title-bold">text</span> us`
475
- : "us"
476
- }
477
- </div>
478
- <div class="type-gradient__icon">${ChevronIconWhite}</div>
479
- </div>
480
- </div>
481
- `
482
- : ""
483
- }
484
- <div class="type-hey__bottom-info">
485
- Online <span class="heavy-blue">24 hours</span> a day, <span class="heavy-blue">7</span> days a week</div>
486
- </div>
487
- </div>
488
- <div class="type-hey__chat-container" @click=${
489
- this.onChatTapped
490
- }>${ChatBlueBttnIcon}</div>
491
- </div>
492
- `;
493
- }
494
-
495
- return html` <div class="vertical-pill-list">
496
- <button @click=${this.onClickMinimize} class="minimize-bttn">
497
- <div class="chevron-down">${ChevronIconBlack}</div>
498
- </button>
499
- ${this.hasEmailEnabled
500
- ? this.renderPillVertical(
501
- html`
502
- <div class="vertical-pill-icon">${FilledEmailIcon}</div>
503
- <div class="vertical-pill-title">
504
- <span class="vertical-pill-bold">Email</span> an agent
505
- </div>
506
- `,
507
- this.onClickEmailOption
508
- )
509
- : ""}
510
- ${this.hasChatEnabled
511
- ? this.renderPillVertical(
512
- html`
513
- <div class="vertical-pill-icon">${FilledChatIcon}</div>
514
- <div class="vertical-pill-title">
515
- <span class="vertical-pill-bold">Chat</span> with us
516
- </div>
517
- `,
518
- this.onChatTapped
519
- )
520
- : ""}
521
- ${this.hasSSTEnabled
522
- ? this.renderPillVertical(
523
- html`
524
- <div class="vertical-pill-icon">${FilledTourIcon}</div>
525
- <div class="vertical-pill-title">
526
- <span class="vertical-pill-bold">Book</span> a tour
527
- </div>
528
- `,
529
- this.onClickSSTOption
530
- )
531
- : ""}
532
- ${this.phoneNumber && this.hasCallUsEnabled
533
- ? this.renderPillVertical(
534
- html`
535
- <div class="vertical-pill-icon">${FilledPhoneIcon}</div>
536
- <div class="vertical-pill-title">
537
- <span class="vertical-pill-bold">Call</span>
538
- ${this.hasTextUsEnabled
539
- ? html`or <span class="vertical-pill-bold">text</span> us`
540
- : "us"}
541
- </div>
542
- `,
543
- this.onClickPhoneOption
544
- )
545
- : ""}
546
- </div>`;
547
- };
548
-
549
- render(): TemplateResult {
550
- installEmailUsWindow();
551
- installTextUsWindow();
552
- installCallUsWindow();
553
-
554
- return html`
555
- <div"
556
- class=${
557
- this.isMobile || this.isMinimized
558
- ? "launcher__mobile-launcher-wrapper"
559
- : "launcher__mini-launcher-wrapper"
560
- }
561
- style=${styleMap(this.launcherStyles)}
562
- >
563
- ${
564
- this.isEmailWindowOpen
565
- ? html`<div class="launcher__window-wrapper">
566
- <email-us-window
567
- chatId="${this.chatId}"
568
- .leadSources="${this.leadSources}"
569
- currentLeadSource="${this.currentLeadSource}"
570
- orgSlug="${this.orgSlug}"
571
- buildingSlug="${this.buildingSlug}"
572
- featureFlagShowDropdown="${this.featureFlagShowDropdown}"
573
- ${ref(this.emailUsWindowRef)}
574
- .buildingId=${this.buildingId}
575
- >
576
- </email-us-window>
577
- </div>`
578
- : ""
579
- }
580
- ${
581
- this.isTextUsWindowOpen
582
- ? html`<div class="launcher__window-wrapper">
583
- <text-us-window
584
- orgSlug="${this.orgSlug}"
585
- buildingSlug="${this.buildingSlug}"
586
- ${ref(this.textUsWindowRef)}
587
- .buildingId=${this.buildingId}
588
- currentLeadSource="${this.currentLeadSource}"
589
- ></text-us-window>
590
- </div>`
591
- : ""
592
- }
593
- ${
594
- this.isSSTWindowOpen
595
- ? html`<div class="launcher__window-wrapper">
596
- <tour-scheduler
597
- chatId="${this.chatId}"
598
- orgSlug="${this.orgSlug}"
599
- buildingSlug="${this.buildingSlug}"
600
- sgtUrl="${this.sgtUrl}"
601
- escortedToursLink="${this.escortedToursLink}"
602
- virtualToursLink="${this.virtualToursLink}"
603
- currentLeadSource="${this.currentLeadSource}"
604
- .leadSources="${this.leadSources}"
605
- .layoutOptions=${this.layoutOptions}
606
- .unitOptions=${this.unitOptions}
607
- .tourTypeOptions=${this.tourTypeOptions}
608
- buildingId=${this.buildingId}
609
- featureFlagShowDropdown="${this.featureFlagShowDropdown}"
610
- ${ref(this.tourSchedulerRef)}
611
- ></tour-scheduler>
612
- </div>`
613
- : ""
614
- }
615
- ${
616
- this.isCallUsWindowOpen
617
- ? html`
618
- <div class="launcher__window-wrapper">
619
- <call-us-window
620
- .onCloseClicked=${this.onClosePhoneWindow}
621
- phoneNumber="${this.phoneNumber}"
622
- .buildingId=${this.buildingId}
623
- chatCallUsHeader="${this.chatCallUsHeader}"
624
- hasTextUsEnabled=${this.hasTextUsEnabled ? true : ""}
625
- currentLeadSource="${this.currentLeadSource}"
626
- ></call-us-window>
627
- </div>
628
- `
629
- : ""
630
- }
631
- ${!this.isCallToActionWindowOpen() ? this.renderActionPills() : ""}
632
- </div>
633
- `;
634
- }
635
- }
636
-
637
- export const installLauncher = (): void => {
638
- if (!window.customElements.get("meetelise-launcher")) {
639
- window.customElements.define("meetelise-launcher", Launcher);
640
- }
641
- };