@meetelise/chat 1.20.84 → 1.20.85
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.
- package/package.json +3 -1
- package/public/demo/index.html +8 -2
- package/public/dist/index.js +477 -231
- package/public/dist/index.js.LICENSE.txt +17 -0
- package/src/MyPubnub.ts +236 -0
- package/src/WebComponent/me-chat.ts +193 -67
- package/src/WebComponent/pubnub-chat-styles.ts +172 -0
- package/src/WebComponent/pubnub-chat.ts +155 -0
- package/src/fetchFeatureFlag.ts +21 -0
- package/src/svgIcons.ts +9 -0
|
@@ -10,6 +10,23 @@ object-assign
|
|
|
10
10
|
http://jedwatson.github.io/classnames
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/*! *****************************************************************************
|
|
14
|
+
Copyright (c) Microsoft Corporation.
|
|
15
|
+
|
|
16
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
17
|
+
purpose with or without fee is hereby granted.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
20
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
21
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
22
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
23
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
24
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
25
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
26
|
+
***************************************************************************** */
|
|
27
|
+
|
|
28
|
+
/*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */
|
|
29
|
+
|
|
13
30
|
/**
|
|
14
31
|
* @license
|
|
15
32
|
* Copyright 2017 Google LLC
|
package/src/MyPubnub.ts
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { AxiosError } from "axios";
|
|
2
|
+
import Pubnub, { ListenerParameters, MessageEvent } from "pubnub";
|
|
3
|
+
|
|
4
|
+
import axios from "axios";
|
|
5
|
+
import { Building } from "./fetchBuildingInfo";
|
|
6
|
+
|
|
7
|
+
interface TokenResponse {
|
|
8
|
+
auth: {
|
|
9
|
+
result: {
|
|
10
|
+
token: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
keys: {
|
|
14
|
+
subscribe_key: string;
|
|
15
|
+
publish_key: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ChatMessage {
|
|
20
|
+
channel: string;
|
|
21
|
+
message: {
|
|
22
|
+
text: string;
|
|
23
|
+
customType: string;
|
|
24
|
+
};
|
|
25
|
+
publisher: string;
|
|
26
|
+
subscription: string;
|
|
27
|
+
timetoken: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class MyPubnub {
|
|
31
|
+
private apiHost = "https://app.meetelise.com";
|
|
32
|
+
|
|
33
|
+
private building: Building | null = null;
|
|
34
|
+
private buildingSlug: string;
|
|
35
|
+
private orgSlug: string;
|
|
36
|
+
|
|
37
|
+
pubnub: Pubnub | null = null;
|
|
38
|
+
leadUserId = "";
|
|
39
|
+
channel = "";
|
|
40
|
+
|
|
41
|
+
chatListener:
|
|
42
|
+
| ((res: { messages: ChatMessage[]; isLoading: boolean }) => void)
|
|
43
|
+
| null = null;
|
|
44
|
+
|
|
45
|
+
messages: ChatMessage[] = [];
|
|
46
|
+
listenerParams: ListenerParameters = {
|
|
47
|
+
message: (messageEvent: MessageEvent) => {
|
|
48
|
+
this.messages = [
|
|
49
|
+
...this.messages,
|
|
50
|
+
{
|
|
51
|
+
channel: messageEvent.channel,
|
|
52
|
+
message: messageEvent.message,
|
|
53
|
+
publisher: messageEvent.publisher,
|
|
54
|
+
subscription: messageEvent.subscription,
|
|
55
|
+
timetoken: +messageEvent.timetoken,
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
const isWaitingForEliseResponse = messageEvent.publisher !== "eliseai";
|
|
59
|
+
this.chatListener?.({
|
|
60
|
+
messages: this.messages,
|
|
61
|
+
isLoading: isWaitingForEliseResponse,
|
|
62
|
+
});
|
|
63
|
+
this.isLoadingMessages = isWaitingForEliseResponse;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
isLoadingMessages = false;
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
orgSlug: string,
|
|
70
|
+
buildingSlug: string,
|
|
71
|
+
buildingDetails: Building
|
|
72
|
+
) {
|
|
73
|
+
this.orgSlug = orgSlug;
|
|
74
|
+
this.buildingSlug = buildingSlug;
|
|
75
|
+
this.building = buildingDetails;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
addChatListener(
|
|
79
|
+
listener: (response: {
|
|
80
|
+
messages: ChatMessage[];
|
|
81
|
+
isLoading: boolean;
|
|
82
|
+
}) => void
|
|
83
|
+
): void {
|
|
84
|
+
this.chatListener = listener;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async initializePubnub(): Promise<Pubnub | undefined> {
|
|
88
|
+
//const currentChatId = getChatID(this.orgSlug, this.buildingSlug);
|
|
89
|
+
const existingUserId = localStorage.getItem("_uetsid"); // apartments.com user_id
|
|
90
|
+
const uniqueUserId =
|
|
91
|
+
existingUserId ?? Math.floor(Math.random() * 1000000000);
|
|
92
|
+
|
|
93
|
+
this.leadUserId = `lead_${uniqueUserId}_${this.buildingSlug}`;
|
|
94
|
+
this.channel = `webchat_${this.leadUserId}`;
|
|
95
|
+
|
|
96
|
+
const pubnubToken = await this.fetchToken(this.leadUserId, this.channel);
|
|
97
|
+
|
|
98
|
+
// These keys are OK to expose live, the authKey generated by the BE is what
|
|
99
|
+
// is used to authenticate the user. Ideally, should also add rate limiting
|
|
100
|
+
// and/or IP whitelisting to the BE endpoint that generates the token.
|
|
101
|
+
this.pubnub = new Pubnub({
|
|
102
|
+
publishKey: pubnubToken.keys.publish_key,
|
|
103
|
+
subscribeKey: pubnubToken.keys.subscribe_key,
|
|
104
|
+
userId: this.leadUserId,
|
|
105
|
+
authKey: pubnubToken.auth.result.token,
|
|
106
|
+
});
|
|
107
|
+
this.withAuthToken(() => new Promise(() => this.handleChatListeners()));
|
|
108
|
+
await this.withAuthToken(() => this.getChannelHistory());
|
|
109
|
+
return this.pubnub;
|
|
110
|
+
}
|
|
111
|
+
async fetchToken(lead: string, channel: string): Promise<TokenResponse> {
|
|
112
|
+
const response = await axios.get(
|
|
113
|
+
`${this.apiHost}/platformApi/webchat/pn/request-token?user_id=${lead}&channel=${channel}`
|
|
114
|
+
);
|
|
115
|
+
return response.data;
|
|
116
|
+
}
|
|
117
|
+
async fetchChannelExists(channel: string): Promise<boolean> {
|
|
118
|
+
const response = await axios.get(
|
|
119
|
+
`${this.apiHost}/platformApi/webchat/check-channel-exists?channel_name=${channel}`
|
|
120
|
+
);
|
|
121
|
+
return response.data;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async withAuthToken(apiRequestFunc: () => Promise<void>): Promise<void> {
|
|
125
|
+
try {
|
|
126
|
+
await apiRequestFunc();
|
|
127
|
+
} catch (error: unknown) {
|
|
128
|
+
// only want to retry with new token if the error is a 403
|
|
129
|
+
if (
|
|
130
|
+
error instanceof AxiosError &&
|
|
131
|
+
error &&
|
|
132
|
+
error.response &&
|
|
133
|
+
error.response.status === 403
|
|
134
|
+
) {
|
|
135
|
+
try {
|
|
136
|
+
if (!this.pubnub || !this.leadUserId || !this.channel) return;
|
|
137
|
+
|
|
138
|
+
const newToken = await this.fetchToken(this.leadUserId, this.channel);
|
|
139
|
+
if (!newToken) return;
|
|
140
|
+
|
|
141
|
+
this.pubnub.setAuthKey(newToken.auth.result.token);
|
|
142
|
+
|
|
143
|
+
await apiRequestFunc();
|
|
144
|
+
} catch (retryError) {
|
|
145
|
+
//onsole.error(retryError);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async getChannelHistory(): Promise<void> {
|
|
152
|
+
try {
|
|
153
|
+
const response: Pubnub.FetchMessagesResponse = await new Promise(
|
|
154
|
+
(resolve, reject) => {
|
|
155
|
+
if (!this.pubnub || !this.channel) return;
|
|
156
|
+
this.pubnub.fetchMessages(
|
|
157
|
+
{
|
|
158
|
+
channels: [this.channel],
|
|
159
|
+
count: 100,
|
|
160
|
+
},
|
|
161
|
+
(status, response) => {
|
|
162
|
+
if (status.error) {
|
|
163
|
+
reject(status);
|
|
164
|
+
} else {
|
|
165
|
+
resolve(response);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (this.channel && Object.keys(response.channels).length !== 0) {
|
|
173
|
+
const currentChannelMessages = response.channels[this.channel];
|
|
174
|
+
const parsedCurrentChannelMessages: ChatMessage[] = [];
|
|
175
|
+
currentChannelMessages.forEach((message) => {
|
|
176
|
+
if (message.uuid) {
|
|
177
|
+
parsedCurrentChannelMessages.push({
|
|
178
|
+
channel: message.channel,
|
|
179
|
+
message: message.message,
|
|
180
|
+
publisher: message.uuid,
|
|
181
|
+
subscription: message.channel,
|
|
182
|
+
timetoken: +message.timetoken,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
this.messages = parsedCurrentChannelMessages;
|
|
187
|
+
this.chatListener?.({ messages: this.messages, isLoading: false });
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
// Handle the error here
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
handleChatListeners = (): void => {
|
|
195
|
+
if (!this.pubnub || !this.channel) return;
|
|
196
|
+
this.pubnub.subscribe({ channels: [this.channel] });
|
|
197
|
+
this.pubnub.addListener(this.listenerParams);
|
|
198
|
+
};
|
|
199
|
+
removeChatListeners = (): void => {
|
|
200
|
+
if (this.pubnub && this.channel) {
|
|
201
|
+
this.pubnub.unsubscribe({ channels: [this.channel] });
|
|
202
|
+
this.pubnub.removeListener(this.listenerParams);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
sendMessage = async (message: string): Promise<void> => {
|
|
207
|
+
if (message) {
|
|
208
|
+
if (!this.pubnub) {
|
|
209
|
+
// ONLY create/gets a chat session if user actually wants to chat
|
|
210
|
+
const myPubnub = await this.initializePubnub();
|
|
211
|
+
if (!myPubnub) return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
await this.withAuthToken(async () => {
|
|
215
|
+
if (!this.pubnub || !this.channel) return;
|
|
216
|
+
await this.pubnub.publish({
|
|
217
|
+
channel: this.channel,
|
|
218
|
+
message: {
|
|
219
|
+
text: message,
|
|
220
|
+
customType: "lead_message",
|
|
221
|
+
buildingId: this.building?.id,
|
|
222
|
+
buildingSlug: this.buildingSlug,
|
|
223
|
+
userId: this.building?.userId, // this userid is actually the AI user!
|
|
224
|
+
// leadSource: DEFAULT_LEAD_SOURCE,
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
if (this.isLoadingMessages === false) this.isLoadingMessages = true;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
isLeadMessage = (message: ChatMessage): boolean =>
|
|
232
|
+
message.publisher.includes("lead_") &&
|
|
233
|
+
message.message.customType === "lead_message";
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export default MyPubnub;
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
FeatureFlagsShowDropdown,
|
|
14
14
|
fetchFeatureFlagShowMarketingSourceDropdown,
|
|
15
15
|
fetchFeatureFlagUsePhoneNumberBySource,
|
|
16
|
+
fetchFeatureFlagUsePubnub,
|
|
16
17
|
} from "../fetchFeatureFlag";
|
|
17
18
|
import fetchWebchatPreferences, {
|
|
18
19
|
DesignConcepts,
|
|
@@ -37,10 +38,16 @@ import addMinutes from "date-fns/addMinutes";
|
|
|
37
38
|
import formatISO from "date-fns/formatISO";
|
|
38
39
|
import fetchLeadSources from "../fetchLeadSources";
|
|
39
40
|
import { formatPhoneNumber } from "./actions/formatPhoneNumber";
|
|
41
|
+
import MyPubnub from "../MyPubnub";
|
|
40
42
|
|
|
41
43
|
import "./actions/minimize-expand-button";
|
|
42
44
|
import "./launcher/mobile-launcher";
|
|
45
|
+
import "./pubnub-chat";
|
|
43
46
|
|
|
47
|
+
enum ChatProviders {
|
|
48
|
+
TALKJS = "talkjs",
|
|
49
|
+
PUBNUB = "pubnub",
|
|
50
|
+
}
|
|
44
51
|
@customElement("me-chat")
|
|
45
52
|
export class MEChat extends LitElement {
|
|
46
53
|
static styles = css`
|
|
@@ -66,7 +73,8 @@ export class MEChat extends LitElement {
|
|
|
66
73
|
justify-content: space-between;
|
|
67
74
|
gap: 32px;
|
|
68
75
|
}
|
|
69
|
-
#
|
|
76
|
+
#chatAdditionalActionsTalkjs,
|
|
77
|
+
#chatAdditionalActionsPubnub {
|
|
70
78
|
position: fixed;
|
|
71
79
|
box-sizing: border-box;
|
|
72
80
|
|
|
@@ -78,7 +86,8 @@ export class MEChat extends LitElement {
|
|
|
78
86
|
|
|
79
87
|
z-index: 1000000000;
|
|
80
88
|
}
|
|
81
|
-
#
|
|
89
|
+
#chatAdditionalActionsPubnub::after,
|
|
90
|
+
#chatAdditionalActionsTalkjs::after {
|
|
82
91
|
content: "";
|
|
83
92
|
position: absolute;
|
|
84
93
|
top: -6px;
|
|
@@ -88,6 +97,10 @@ export class MEChat extends LitElement {
|
|
|
88
97
|
border-bottom: 22px solid transparent;
|
|
89
98
|
border-right: 30px solid black;
|
|
90
99
|
}
|
|
100
|
+
#pubnub-bottom {
|
|
101
|
+
position: fixed;
|
|
102
|
+
bottom: 0;
|
|
103
|
+
}
|
|
91
104
|
`;
|
|
92
105
|
@property({ type: String })
|
|
93
106
|
private buildingSlug = "";
|
|
@@ -147,6 +160,15 @@ export class MEChat extends LitElement {
|
|
|
147
160
|
@state()
|
|
148
161
|
private talkjsPopupElement: Element | null = null;
|
|
149
162
|
|
|
163
|
+
@state()
|
|
164
|
+
private chatProvider: ChatProviders = ChatProviders.TALKJS;
|
|
165
|
+
|
|
166
|
+
@state()
|
|
167
|
+
private displayPubnubChat = false;
|
|
168
|
+
|
|
169
|
+
@state()
|
|
170
|
+
private myPubnub: MyPubnub | null = null;
|
|
171
|
+
|
|
150
172
|
private yardiDNIScriptInterval: NodeJS.Timer | null = null;
|
|
151
173
|
launcherRef: Ref<Launcher> = createRef();
|
|
152
174
|
|
|
@@ -378,11 +400,7 @@ export class MEChat extends LitElement {
|
|
|
378
400
|
(talkjsPopupElement as HTMLElement).style.zIndex = "99999999999";
|
|
379
401
|
this.popup = popup;
|
|
380
402
|
|
|
381
|
-
|
|
382
|
-
const shouldAutoOpen =
|
|
383
|
-
!autoOpenedTimestamp ||
|
|
384
|
-
(autoOpenedTimestamp && isPast(parseISO(autoOpenedTimestamp)));
|
|
385
|
-
if (building.autoOpenChatWidget && shouldAutoOpen && !isMobile()) {
|
|
403
|
+
if (this.shouldAutoOpenChatWidget(building.autoOpenChatWidget)) {
|
|
386
404
|
this.popup.show();
|
|
387
405
|
this.hideLauncher = true;
|
|
388
406
|
this.hasMounted = true;
|
|
@@ -394,6 +412,18 @@ export class MEChat extends LitElement {
|
|
|
394
412
|
}
|
|
395
413
|
};
|
|
396
414
|
|
|
415
|
+
private shouldAutoOpenChatWidget = (
|
|
416
|
+
buildingHasAutoOpen: boolean
|
|
417
|
+
): boolean => {
|
|
418
|
+
const autoOpenedTimestamp = sessionStorage.getItem("autoOpenedTimestamp");
|
|
419
|
+
const shouldAutoOpen =
|
|
420
|
+
!autoOpenedTimestamp ||
|
|
421
|
+
(autoOpenedTimestamp && isPast(parseISO(autoOpenedTimestamp)));
|
|
422
|
+
if (buildingHasAutoOpen && shouldAutoOpen && !isMobile()) {
|
|
423
|
+
return true;
|
|
424
|
+
}
|
|
425
|
+
return false;
|
|
426
|
+
};
|
|
397
427
|
/**
|
|
398
428
|
* Remove the instance from the screen.
|
|
399
429
|
*
|
|
@@ -432,26 +462,70 @@ export class MEChat extends LitElement {
|
|
|
432
462
|
this.launcher.style.display = "none";
|
|
433
463
|
}
|
|
434
464
|
|
|
435
|
-
firstUpdated = (): void => {
|
|
436
|
-
|
|
465
|
+
firstUpdated = async (): Promise<void> => {
|
|
466
|
+
const usePubnubProviderFlag = await fetchFeatureFlagUsePubnub(
|
|
467
|
+
this.buildingSlug
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
if (usePubnubProviderFlag) {
|
|
471
|
+
this.chatProvider = ChatProviders.PUBNUB;
|
|
472
|
+
this.initializePubnubVariables();
|
|
473
|
+
} else {
|
|
474
|
+
this.initializeInstanceVariables();
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
initializePubnubVariables = async (): Promise<void> => {
|
|
479
|
+
await this.setBuildingDerivedInfo();
|
|
480
|
+
if (!this.building) return;
|
|
481
|
+
|
|
482
|
+
const pubnubRaw = new MyPubnub(
|
|
483
|
+
this.orgSlug,
|
|
484
|
+
this.buildingSlug,
|
|
485
|
+
this.building
|
|
486
|
+
);
|
|
487
|
+
await pubnubRaw.initializePubnub();
|
|
488
|
+
this.myPubnub = pubnubRaw;
|
|
489
|
+
this.attachOnClickToLauncher();
|
|
490
|
+
if (this.shouldAutoOpenChatWidget(this.building.autoOpenChatWidget)) {
|
|
491
|
+
this.displayPubnubChat = true;
|
|
492
|
+
this.hideLauncher = true;
|
|
493
|
+
this.hasMounted = true;
|
|
494
|
+
sessionStorage.setItem(
|
|
495
|
+
"autoOpenedTimestamp",
|
|
496
|
+
formatISO(addMinutes(new Date(), 15))
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
this.isLoading = false;
|
|
437
500
|
};
|
|
438
501
|
|
|
439
502
|
handleContactClicked = (e: MouseEvent): void => {
|
|
440
|
-
this.
|
|
503
|
+
if (this.chatProvider === ChatProviders.TALKJS) {
|
|
504
|
+
this.popup?.hide();
|
|
505
|
+
} else if (this.chatProvider === ChatProviders.PUBNUB) {
|
|
506
|
+
this.displayPubnubChat = false;
|
|
507
|
+
}
|
|
441
508
|
this.hideLauncher = false;
|
|
442
509
|
|
|
443
510
|
this.launcherRef.value?.onClickEmailOption(e);
|
|
444
511
|
};
|
|
445
512
|
|
|
446
513
|
handleTourClicked = (e: MouseEvent): void => {
|
|
447
|
-
this.
|
|
514
|
+
if (this.chatProvider === ChatProviders.TALKJS) {
|
|
515
|
+
this.popup?.hide();
|
|
516
|
+
} else if (this.chatProvider === ChatProviders.PUBNUB) {
|
|
517
|
+
this.displayPubnubChat = false;
|
|
518
|
+
}
|
|
448
519
|
this.hideLauncher = false;
|
|
449
|
-
|
|
450
520
|
this.launcherRef.value?.onClickSSTOption(e);
|
|
451
521
|
};
|
|
452
522
|
|
|
453
523
|
handleContactTabClicked = (e: MouseEvent): void => {
|
|
454
|
-
this.
|
|
524
|
+
if (this.chatProvider === ChatProviders.TALKJS) {
|
|
525
|
+
this.popup?.hide();
|
|
526
|
+
} else if (this.chatProvider === ChatProviders.PUBNUB) {
|
|
527
|
+
this.displayPubnubChat = false;
|
|
528
|
+
}
|
|
455
529
|
this.hideLauncher = false;
|
|
456
530
|
|
|
457
531
|
this.launcherRef.value?.onClickPhoneOption(e);
|
|
@@ -461,14 +535,25 @@ export class MEChat extends LitElement {
|
|
|
461
535
|
// For the top header contact, we change its pos based on the current x and y
|
|
462
536
|
// of the talkjs popup - so we must adjust its coords on resize and mount
|
|
463
537
|
adjustTopHeaderContactCoords = (): void => {
|
|
464
|
-
|
|
538
|
+
const headerRef = this.shadowRoot?.getElementById(
|
|
539
|
+
this.chatProvider === ChatProviders.TALKJS
|
|
540
|
+
? "chatAdditionalActionsTalkjs"
|
|
541
|
+
: "chatAdditionalActionsPubnub"
|
|
542
|
+
);
|
|
543
|
+
if (!headerRef) return;
|
|
544
|
+
if (this.chatProvider === ChatProviders.TALKJS && this.talkjsPopupElement) {
|
|
465
545
|
const talkjsPopupCoords = this.talkjsPopupElement.getBoundingClientRect();
|
|
466
|
-
const headerRef = this.shadowRoot?.getElementById(
|
|
467
|
-
"chatAdditionalActions"
|
|
468
|
-
);
|
|
469
|
-
if (!headerRef) return;
|
|
470
546
|
headerRef.style.left = `${talkjsPopupCoords.left + 20}px`;
|
|
471
547
|
headerRef.style.top = `${talkjsPopupCoords.bottom - 24}px`;
|
|
548
|
+
} else if (this.chatProvider === ChatProviders.PUBNUB) {
|
|
549
|
+
const pubnubContainerElement = this.shadowRoot
|
|
550
|
+
?.getElementById("pubnub-chat")
|
|
551
|
+
?.shadowRoot?.getElementById("pubnub-chat-container");
|
|
552
|
+
|
|
553
|
+
const pubnubPopupCoords = pubnubContainerElement?.getBoundingClientRect();
|
|
554
|
+
if (!pubnubPopupCoords) return;
|
|
555
|
+
headerRef.style.left = `${pubnubPopupCoords.left}px`;
|
|
556
|
+
headerRef.style.top = `${pubnubPopupCoords.bottom}px`;
|
|
472
557
|
}
|
|
473
558
|
};
|
|
474
559
|
connectedCallback(): void {
|
|
@@ -476,6 +561,7 @@ export class MEChat extends LitElement {
|
|
|
476
561
|
window.addEventListener("resize", this.adjustTopHeaderContactCoords);
|
|
477
562
|
}
|
|
478
563
|
disconnectedCallback(): void {
|
|
564
|
+
this.myPubnub?.removeChatListeners();
|
|
479
565
|
window.removeEventListener("resize", this.adjustTopHeaderContactCoords);
|
|
480
566
|
super.disconnectedCallback();
|
|
481
567
|
}
|
|
@@ -501,6 +587,34 @@ export class MEChat extends LitElement {
|
|
|
501
587
|
EliseAI widget that allows you to chat with a virtual assistant, book
|
|
502
588
|
a tour, contact the leasing office, and more.
|
|
503
589
|
</div>
|
|
590
|
+
|
|
591
|
+
${
|
|
592
|
+
this.chatProvider === ChatProviders.PUBNUB &&
|
|
593
|
+
this.displayPubnubChat &&
|
|
594
|
+
this.myPubnub
|
|
595
|
+
? html`
|
|
596
|
+
<pubnub-chat
|
|
597
|
+
id="pubnub-chat"
|
|
598
|
+
.channel=${this.myPubnub.channel}
|
|
599
|
+
.myPubnub=${this.myPubnub}
|
|
600
|
+
.buildingSlug=${this.buildingSlug}
|
|
601
|
+
.building=${this.building}
|
|
602
|
+
.brandColor=${this.brandColor}
|
|
603
|
+
.onClickExit=${() => {
|
|
604
|
+
this.displayPubnubChat = false;
|
|
605
|
+
this.hideLauncher = false;
|
|
606
|
+
}}
|
|
607
|
+
.onMount=${() => {
|
|
608
|
+
this.adjustTopHeaderContactCoords();
|
|
609
|
+
}}
|
|
610
|
+
></pubnub-chat>
|
|
611
|
+
${this.renderChatAdditionalActions(
|
|
612
|
+
"chatAdditionalActionsPubnub",
|
|
613
|
+
showChatAdditionalActions
|
|
614
|
+
)}
|
|
615
|
+
`
|
|
616
|
+
: ""
|
|
617
|
+
}
|
|
504
618
|
<div
|
|
505
619
|
class=${classMap({
|
|
506
620
|
launcherContainer: true,
|
|
@@ -568,54 +682,65 @@ export class MEChat extends LitElement {
|
|
|
568
682
|
}
|
|
569
683
|
|
|
570
684
|
</div>
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
.onClickEmailOption=${this.handleContactClicked}
|
|
581
|
-
.onClickPhoneOption=${this.handleContactTabClicked}
|
|
582
|
-
.onClickSSTOption=${this.handleTourClicked}
|
|
583
|
-
.isMobile=${this.isMobile}
|
|
584
|
-
.brandColor=${this.brandColor}
|
|
585
|
-
.hideChat=${true}
|
|
586
|
-
.hasChatEnabled=${
|
|
587
|
-
!this.building?.chatWidgets
|
|
588
|
-
? true
|
|
589
|
-
: this.building?.chatWidgets.includes("CHAT")
|
|
590
|
-
}
|
|
591
|
-
.hasEmailEnabled=${
|
|
592
|
-
!this.building?.chatWidgets
|
|
593
|
-
? true
|
|
594
|
-
: this.building?.chatWidgets.includes("EMAIL")
|
|
595
|
-
}
|
|
596
|
-
.hasCallUsEnabled=${
|
|
597
|
-
!this.building?.chatWidgets
|
|
598
|
-
? true
|
|
599
|
-
: this.building?.chatWidgets.includes("CALL")
|
|
600
|
-
}
|
|
601
|
-
.hasSSTEnabled=${
|
|
602
|
-
!this.building?.chatWidgets
|
|
603
|
-
? true
|
|
604
|
-
: this.building?.chatWidgets.includes("SST")
|
|
605
|
-
}
|
|
606
|
-
></mobile-launcher>
|
|
607
|
-
<minimize-expand-button
|
|
608
|
-
.brandColor=${this.brandColor}
|
|
609
|
-
.onClick=${() => {
|
|
610
|
-
this.popup?.hide();
|
|
611
|
-
this.hideLauncher = false;
|
|
612
|
-
}}
|
|
613
|
-
></minimize-expand-button>
|
|
614
|
-
</div>
|
|
685
|
+
${
|
|
686
|
+
this.chatProvider === ChatProviders.TALKJS
|
|
687
|
+
? this.renderChatAdditionalActions(
|
|
688
|
+
"chatAdditionalActionsTalkjs",
|
|
689
|
+
showChatAdditionalActions
|
|
690
|
+
)
|
|
691
|
+
: ""
|
|
692
|
+
}
|
|
693
|
+
|
|
615
694
|
</meta>
|
|
616
695
|
`;
|
|
617
696
|
}
|
|
618
697
|
|
|
698
|
+
private renderChatAdditionalActions = (
|
|
699
|
+
id: string,
|
|
700
|
+
showChatAdditionalActions: boolean
|
|
701
|
+
): TemplateResult => {
|
|
702
|
+
return html` <div
|
|
703
|
+
id=${id}
|
|
704
|
+
class=${classMap({
|
|
705
|
+
["showTab"]: showChatAdditionalActions,
|
|
706
|
+
["hideTab"]: !showChatAdditionalActions,
|
|
707
|
+
})}
|
|
708
|
+
>
|
|
709
|
+
<mobile-launcher
|
|
710
|
+
.onClickMinimize=${this.onClickMinimize}
|
|
711
|
+
.onClickEmailOption=${this.handleContactClicked}
|
|
712
|
+
.onClickPhoneOption=${this.handleContactTabClicked}
|
|
713
|
+
.onClickSSTOption=${this.handleTourClicked}
|
|
714
|
+
.isMobile=${this.isMobile}
|
|
715
|
+
.brandColor=${this.brandColor}
|
|
716
|
+
.hideChat=${true}
|
|
717
|
+
.hasChatEnabled=${!this.building?.chatWidgets
|
|
718
|
+
? true
|
|
719
|
+
: this.building?.chatWidgets.includes("CHAT")}
|
|
720
|
+
.hasEmailEnabled=${!this.building?.chatWidgets
|
|
721
|
+
? true
|
|
722
|
+
: this.building?.chatWidgets.includes("EMAIL")}
|
|
723
|
+
.hasCallUsEnabled=${!this.building?.chatWidgets
|
|
724
|
+
? true
|
|
725
|
+
: this.building?.chatWidgets.includes("CALL")}
|
|
726
|
+
.hasSSTEnabled=${!this.building?.chatWidgets
|
|
727
|
+
? true
|
|
728
|
+
: this.building?.chatWidgets.includes("SST")}
|
|
729
|
+
></mobile-launcher>
|
|
730
|
+
<minimize-expand-button
|
|
731
|
+
.brandColor=${this.brandColor}
|
|
732
|
+
.onClick=${() => {
|
|
733
|
+
if (this.chatProvider === ChatProviders.PUBNUB) {
|
|
734
|
+
this.displayPubnubChat = false;
|
|
735
|
+
} else if (this.chatProvider === ChatProviders.TALKJS) {
|
|
736
|
+
this.popup?.hide();
|
|
737
|
+
}
|
|
738
|
+
this.hideLauncher = false;
|
|
739
|
+
}}
|
|
740
|
+
></minimize-expand-button>
|
|
741
|
+
</div>`;
|
|
742
|
+
};
|
|
743
|
+
|
|
619
744
|
private attachOnClickToLauncher = () => {
|
|
620
745
|
const launcher = this.launcherRef.value;
|
|
621
746
|
if (!launcher) {
|
|
@@ -623,12 +748,13 @@ export class MEChat extends LitElement {
|
|
|
623
748
|
}
|
|
624
749
|
|
|
625
750
|
launcher.onChatTapped = async () => {
|
|
626
|
-
if (
|
|
627
|
-
|
|
751
|
+
if (this.chatProvider === ChatProviders.PUBNUB) {
|
|
752
|
+
this.displayPubnubChat = true;
|
|
753
|
+
} else if (this.chatProvider === ChatProviders.TALKJS) {
|
|
754
|
+
if (!this.popup) return;
|
|
755
|
+
this.popup.show();
|
|
756
|
+
this.analytics?.ping("open");
|
|
628
757
|
}
|
|
629
|
-
|
|
630
|
-
this.popup.show();
|
|
631
|
-
this.analytics?.ping("open");
|
|
632
758
|
this.hideLauncher = true;
|
|
633
759
|
this.hasMounted = true;
|
|
634
760
|
};
|