@meetelise/chat 1.20.91 → 1.20.93
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 +1 -1
- package/public/dist/index.js +76 -76
- package/src/MyPubnub.ts +124 -15
- package/src/WebComponent/me-chat.ts +5 -1
- package/src/WebComponent/pubnub-chat-styles.ts +1 -1
- package/src/analytics.ts +39 -0
- package/src/fetchBuildingInfo.ts +14 -13
package/src/MyPubnub.ts
CHANGED
|
@@ -9,6 +9,7 @@ import addHours from "date-fns/addHours";
|
|
|
9
9
|
import isAfter from "date-fns/isAfter";
|
|
10
10
|
import formatISO from "date-fns/formatISO";
|
|
11
11
|
import isBefore from "date-fns/isBefore";
|
|
12
|
+
import { LogType, sendLoggingEvent } from "./analytics";
|
|
12
13
|
|
|
13
14
|
interface TokenResponse {
|
|
14
15
|
auth: {
|
|
@@ -44,8 +45,11 @@ class MyPubnub {
|
|
|
44
45
|
|
|
45
46
|
private building: Building | null = null;
|
|
46
47
|
private buildingSlug: string;
|
|
48
|
+
private orgSlug: string;
|
|
47
49
|
private ttlHours = 24;
|
|
48
50
|
|
|
51
|
+
private eliseResponseTimeout: NodeJS.Timeout | null = null;
|
|
52
|
+
|
|
49
53
|
pubnub: Pubnub | null = null;
|
|
50
54
|
leadUserId = "";
|
|
51
55
|
channel = "";
|
|
@@ -72,14 +76,22 @@ class MyPubnub {
|
|
|
72
76
|
messages: this.messages,
|
|
73
77
|
isLoading: isWaitingForEliseResponse,
|
|
74
78
|
});
|
|
79
|
+
if (!isWaitingForEliseResponse && this.eliseResponseTimeout) {
|
|
80
|
+
clearTimeout(this.eliseResponseTimeout);
|
|
81
|
+
}
|
|
75
82
|
this.isLoadingMessages = isWaitingForEliseResponse;
|
|
76
83
|
},
|
|
77
84
|
};
|
|
78
85
|
isLoadingMessages = false;
|
|
79
86
|
|
|
80
|
-
constructor(
|
|
87
|
+
constructor(
|
|
88
|
+
buildingSlug: string,
|
|
89
|
+
buildingDetails: Building,
|
|
90
|
+
orgSlug: string
|
|
91
|
+
) {
|
|
81
92
|
this.buildingSlug = buildingSlug;
|
|
82
93
|
this.building = buildingDetails;
|
|
94
|
+
this.orgSlug = orgSlug;
|
|
83
95
|
}
|
|
84
96
|
|
|
85
97
|
addChatListener(
|
|
@@ -95,7 +107,17 @@ class MyPubnub {
|
|
|
95
107
|
const storedChatKeyValues = this.getChatStorageKey();
|
|
96
108
|
if (!storedChatKeyValues.leadId) {
|
|
97
109
|
// eslint-disable-next-line no-console
|
|
98
|
-
|
|
110
|
+
sendLoggingEvent({
|
|
111
|
+
logTitle: "PUBNUB_ERROR_FETCHING_STORAGE_KEY",
|
|
112
|
+
logData: {
|
|
113
|
+
channel: this.channel,
|
|
114
|
+
eliseaiLocalStorageValue: storedChatKeyValues,
|
|
115
|
+
leadUserId: this.leadUserId,
|
|
116
|
+
},
|
|
117
|
+
logType: LogType.warn,
|
|
118
|
+
buildingSlug: this.buildingSlug,
|
|
119
|
+
orgSlug: this.orgSlug,
|
|
120
|
+
});
|
|
99
121
|
return;
|
|
100
122
|
}
|
|
101
123
|
|
|
@@ -115,6 +137,7 @@ class MyPubnub {
|
|
|
115
137
|
}
|
|
116
138
|
|
|
117
139
|
const pubnubToken = await this.fetchToken(this.leadUserId, this.channel);
|
|
140
|
+
if (!pubnubToken) return;
|
|
118
141
|
|
|
119
142
|
// These keys are OK to expose live, the authKey generated by the BE is what
|
|
120
143
|
// is used to authenticate the user. Ideally, should also add rate limiting
|
|
@@ -129,17 +152,42 @@ class MyPubnub {
|
|
|
129
152
|
await this.withAuthToken(() => this.getChannelHistory());
|
|
130
153
|
return this.pubnub;
|
|
131
154
|
}
|
|
132
|
-
async fetchToken(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
155
|
+
async fetchToken(
|
|
156
|
+
lead: string,
|
|
157
|
+
channel: string
|
|
158
|
+
): Promise<TokenResponse | null> {
|
|
159
|
+
try {
|
|
160
|
+
const response = await axios.get(
|
|
161
|
+
`${this.apiHost}/platformApi/webchat/pn/request-token?user_id=${lead}&channel=${channel}`
|
|
162
|
+
);
|
|
163
|
+
return response.data;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
sendLoggingEvent({
|
|
166
|
+
logTitle: "PUBNUB_ERROR_FETCHING_TOKEN",
|
|
167
|
+
logData: { error },
|
|
168
|
+
logType: LogType.error,
|
|
169
|
+
buildingSlug: this.buildingSlug,
|
|
170
|
+
orgSlug: this.orgSlug,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
137
174
|
}
|
|
138
175
|
async fetchChannelExists(channel: string): Promise<boolean> {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
176
|
+
try {
|
|
177
|
+
const response = await axios.get(
|
|
178
|
+
`${this.apiHost}/platformApi/webchat/check-channel-exists?channel_name=${channel}`
|
|
179
|
+
);
|
|
180
|
+
return response.data;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
sendLoggingEvent({
|
|
183
|
+
logTitle: "PUBNUB_ERROR_FETCHING_CHANNEL_EXISTS",
|
|
184
|
+
logData: { error },
|
|
185
|
+
logType: LogType.error,
|
|
186
|
+
buildingSlug: this.buildingSlug,
|
|
187
|
+
orgSlug: this.orgSlug,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
143
191
|
}
|
|
144
192
|
|
|
145
193
|
async withAuthToken(apiRequestFunc: () => Promise<void>): Promise<void> {
|
|
@@ -163,7 +211,15 @@ class MyPubnub {
|
|
|
163
211
|
|
|
164
212
|
await apiRequestFunc();
|
|
165
213
|
} catch (retryError) {
|
|
166
|
-
|
|
214
|
+
sendLoggingEvent({
|
|
215
|
+
logTitle: "PUBNUB_ERROR_REFETCHING_TOKEN",
|
|
216
|
+
logData: {
|
|
217
|
+
retryError,
|
|
218
|
+
},
|
|
219
|
+
logType: LogType.error,
|
|
220
|
+
buildingSlug: this.buildingSlug,
|
|
221
|
+
orgSlug: this.orgSlug,
|
|
222
|
+
});
|
|
167
223
|
}
|
|
168
224
|
}
|
|
169
225
|
}
|
|
@@ -181,6 +237,17 @@ class MyPubnub {
|
|
|
181
237
|
},
|
|
182
238
|
(status, response) => {
|
|
183
239
|
if (status.error) {
|
|
240
|
+
sendLoggingEvent({
|
|
241
|
+
logTitle: "PUBNUB_ERROR_FETCHING_HISTORY",
|
|
242
|
+
logData: {
|
|
243
|
+
channel: this.channel,
|
|
244
|
+
status: status,
|
|
245
|
+
response: response,
|
|
246
|
+
},
|
|
247
|
+
logType: LogType.error,
|
|
248
|
+
buildingSlug: this.buildingSlug,
|
|
249
|
+
orgSlug: this.orgSlug,
|
|
250
|
+
});
|
|
184
251
|
reject(status);
|
|
185
252
|
} else {
|
|
186
253
|
resolve(response);
|
|
@@ -208,14 +275,35 @@ class MyPubnub {
|
|
|
208
275
|
this.chatListener?.({ messages: this.messages, isLoading: false });
|
|
209
276
|
}
|
|
210
277
|
} catch (error) {
|
|
211
|
-
|
|
278
|
+
sendLoggingEvent({
|
|
279
|
+
logTitle: "PUBNUB_ERROR_FETCHING_HISTORY",
|
|
280
|
+
logData: { error },
|
|
281
|
+
logType: LogType.error,
|
|
282
|
+
buildingSlug: this.buildingSlug,
|
|
283
|
+
orgSlug: this.orgSlug,
|
|
284
|
+
});
|
|
212
285
|
}
|
|
213
286
|
}
|
|
214
287
|
|
|
215
288
|
handleChatListeners = (): void => {
|
|
216
289
|
if (!this.pubnub || !this.channel) return;
|
|
217
|
-
|
|
218
|
-
|
|
290
|
+
try {
|
|
291
|
+
this.pubnub.subscribe({ channels: [this.channel] });
|
|
292
|
+
this.pubnub.addListener(this.listenerParams);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
sendLoggingEvent({
|
|
295
|
+
logTitle: "PUBNUB_ERROR_ADDING_LISTENER",
|
|
296
|
+
logData: {
|
|
297
|
+
error,
|
|
298
|
+
channel: this.channel,
|
|
299
|
+
leadUserId: this.leadUserId,
|
|
300
|
+
website: location.href,
|
|
301
|
+
},
|
|
302
|
+
logType: LogType.error,
|
|
303
|
+
buildingSlug: this.buildingSlug,
|
|
304
|
+
orgSlug: this.orgSlug,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
219
307
|
};
|
|
220
308
|
removeChatListeners = (): void => {
|
|
221
309
|
if (this.pubnub && this.channel) {
|
|
@@ -234,6 +322,27 @@ class MyPubnub {
|
|
|
234
322
|
|
|
235
323
|
await this.withAuthToken(async () => {
|
|
236
324
|
if (!this.pubnub || !this.channel) return;
|
|
325
|
+
|
|
326
|
+
if (this.eliseResponseTimeout) {
|
|
327
|
+
clearTimeout(this.eliseResponseTimeout);
|
|
328
|
+
this.eliseResponseTimeout = null;
|
|
329
|
+
}
|
|
330
|
+
this.eliseResponseTimeout = setTimeout(() => {
|
|
331
|
+
// eslint-disable-next-line no-console
|
|
332
|
+
console.error("Elise AI did not respond in time...");
|
|
333
|
+
sendLoggingEvent({
|
|
334
|
+
logTitle: "PUBNUB_ERROR_ELISEAI_MESSAGE_TIMEOUT",
|
|
335
|
+
logData: {
|
|
336
|
+
channel: this.channel,
|
|
337
|
+
leadUserId: this.leadUserId,
|
|
338
|
+
message,
|
|
339
|
+
},
|
|
340
|
+
logType: LogType.error,
|
|
341
|
+
buildingSlug: this.buildingSlug,
|
|
342
|
+
orgSlug: this.orgSlug,
|
|
343
|
+
});
|
|
344
|
+
}, 45000); // if after 45 seconds, no message - we log error
|
|
345
|
+
|
|
237
346
|
await this.pubnub.publish({
|
|
238
347
|
channel: this.channel,
|
|
239
348
|
message: {
|
|
@@ -492,7 +492,11 @@ export class MEChat extends LitElement {
|
|
|
492
492
|
return;
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
this.myPubnub = new MyPubnub(
|
|
495
|
+
this.myPubnub = new MyPubnub(
|
|
496
|
+
this.buildingSlug,
|
|
497
|
+
this.building,
|
|
498
|
+
this.orgSlug
|
|
499
|
+
);
|
|
496
500
|
if (this.myPubnub.isChatKeyValid(this.myPubnub.getChatStorageKey(false))) {
|
|
497
501
|
await this.myPubnub.initializePubnub();
|
|
498
502
|
}
|
package/src/analytics.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
1
3
|
declare global {
|
|
2
4
|
interface Window {
|
|
3
5
|
RCTPCampaign?: { CampaignDetails: { Source: string } };
|
|
@@ -86,3 +88,40 @@ export const getCampaignSources = (): CampaignSources => {
|
|
|
86
88
|
yardiCampaignSource,
|
|
87
89
|
};
|
|
88
90
|
};
|
|
91
|
+
|
|
92
|
+
export enum LogType {
|
|
93
|
+
error = "error",
|
|
94
|
+
info = "info",
|
|
95
|
+
warn = "warn",
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const sendLoggingEvent = async ({
|
|
99
|
+
logType,
|
|
100
|
+
buildingSlug,
|
|
101
|
+
orgSlug,
|
|
102
|
+
logTitle,
|
|
103
|
+
logData,
|
|
104
|
+
}: {
|
|
105
|
+
logType?: LogType;
|
|
106
|
+
buildingSlug?: string;
|
|
107
|
+
orgSlug?: string;
|
|
108
|
+
logTitle: string;
|
|
109
|
+
logData: Record<string, unknown>;
|
|
110
|
+
}): Promise<void> => {
|
|
111
|
+
const host = "https://app.meetelise.com";
|
|
112
|
+
await axios.post(
|
|
113
|
+
`${host}/platformApi/webchat/logging`,
|
|
114
|
+
{
|
|
115
|
+
...logData,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
headers: {
|
|
119
|
+
"Content-Type": "application/json",
|
|
120
|
+
"building-slug": buildingSlug ?? "",
|
|
121
|
+
"org-slug": orgSlug ?? "",
|
|
122
|
+
"log-type": logType ?? LogType.error,
|
|
123
|
+
"log-title": logTitle.toUpperCase().replace(/\s/g, "_"),
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
};
|
package/src/fetchBuildingInfo.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
1
3
|
export interface LabeledOption {
|
|
2
4
|
label: string;
|
|
3
5
|
value: string | number;
|
|
@@ -49,20 +51,19 @@ export default async function fetchBuildingInfo(
|
|
|
49
51
|
buildingSlug: string
|
|
50
52
|
): Promise<Building> {
|
|
51
53
|
const host = "https://app.meetelise.com";
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
54
|
+
const buildingUrl = `${host}/api/pub/v1/organization/${orgSlug}/building/${buildingSlug}`;
|
|
55
|
+
const unitsUrl = `${host}/eliseCrmApi/pub/building/${buildingSlug}/units`;
|
|
56
|
+
const layoutsUrl = `${host}/eliseCrmApi/pub/building/${buildingSlug}/layouts`;
|
|
57
|
+
|
|
58
|
+
const [buildingResponse, unitsResponse, layoutsResponse] = await Promise.all([
|
|
59
|
+
axios.get(buildingUrl),
|
|
60
|
+
axios.get(unitsUrl),
|
|
61
|
+
axios.get(layoutsUrl),
|
|
62
|
+
]);
|
|
55
63
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
`${host}/eliseCrmApi/pub/building/${buildingSlug}/units?showAvailableOnly=true`
|
|
60
|
-
);
|
|
61
|
-
const units: UnitV2[] = await unitsResponse.json();
|
|
62
|
-
const layoutsResponse = await fetch(
|
|
63
|
-
`${host}/eliseCrmApi/pub/building/${buildingSlug}/layouts`
|
|
64
|
-
);
|
|
65
|
-
const layouts: string[] = await layoutsResponse.json();
|
|
64
|
+
const building: Building = buildingResponse.data;
|
|
65
|
+
const units: UnitV2[] = unitsResponse.data;
|
|
66
|
+
const layouts: string[] = layoutsResponse.data;
|
|
66
67
|
|
|
67
68
|
building.unitOptionsV2 = units;
|
|
68
69
|
building.layoutOptionsV2 = layouts;
|