@meetelise/chat 1.20.135 → 1.20.136

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/src/MyPubnub.ts CHANGED
@@ -3,14 +3,12 @@ import Pubnub, { ListenerParameters, MessageEvent } from "pubnub";
3
3
 
4
4
  import axios from "axios";
5
5
  import { Building } from "./fetchBuildingInfo";
6
- import parseISO from "date-fns/parseISO";
7
- import { v4 as uuid } from "uuid";
8
6
  import addHours from "date-fns/addHours";
9
7
  import isAfter from "date-fns/isAfter";
10
- import formatISO from "date-fns/formatISO";
11
- import isBefore from "date-fns/isBefore";
12
8
  import { LogType, sendLoggingEvent } from "./analytics";
13
9
 
10
+ import { createChatStorageKey, getChatStorageKey } from "./handleChatIds";
11
+
14
12
  interface TokenResponse {
15
13
  auth: {
16
14
  result: {
@@ -40,7 +38,7 @@ export interface ChatMessage {
40
38
  timetoken: number;
41
39
  }
42
40
 
43
- interface ChatInfo {
41
+ export interface ChatInfo {
44
42
  leadId: string | null;
45
43
  timestamp: Date | null;
46
44
  buildingSlug: string | null;
@@ -116,7 +114,7 @@ class MyPubnub {
116
114
  }
117
115
 
118
116
  async initializePubnub(): Promise<Pubnub | undefined> {
119
- const storedChatKeyValues = this.getChatStorageKey();
117
+ const storedChatKeyValues = getChatStorageKey(true, this.buildingSlug);
120
118
  if (!storedChatKeyValues.leadId) {
121
119
  // eslint-disable-next-line no-console
122
120
  sendLoggingEvent({
@@ -145,9 +143,8 @@ class MyPubnub {
145
143
  addHours(new Date(), this.ttlHours)
146
144
  )
147
145
  ) {
148
- this.createChatStorageKey(this.leadUserId);
146
+ createChatStorageKey(this.buildingSlug, this.leadUserId);
149
147
  }
150
-
151
148
  const pubnubToken = await this.fetchToken(this.leadUserId, this.channel);
152
149
  if (!pubnubToken) return;
153
150
 
@@ -382,80 +379,6 @@ class MyPubnub {
382
379
  isLeadMessage = (message: ChatMessage): boolean =>
383
380
  message.publisher.includes("lead_") &&
384
381
  message.message.customType === "lead_message";
385
-
386
- clearChatStorageKey = (): void =>
387
- localStorage.removeItem("com.eliseai.webchat.slug=" + this.buildingSlug);
388
-
389
- createChatStorageKey = (existingUserId?: string): ChatInfo => {
390
- const storageTimestamp = formatISO(new Date());
391
- const leadUserId = existingUserId ?? `lead_${uuid()}_${this.buildingSlug}`;
392
- localStorage.setItem(
393
- "com.eliseai.webchat.slug=" + this.buildingSlug,
394
- JSON.stringify({
395
- buildingSlug: this.buildingSlug,
396
- leadId: leadUserId,
397
- timestamp: storageTimestamp,
398
- })
399
- );
400
- return {
401
- leadId: leadUserId,
402
- timestamp: parseISO(storageTimestamp),
403
- buildingSlug: this.buildingSlug,
404
- };
405
- };
406
- getChatStorageKey = (createNewIfNotExist = true): ChatInfo => {
407
- const eliseaiLocalStorageValue = localStorage.getItem(
408
- "com.eliseai.webchat.slug=" + this.buildingSlug
409
- );
410
- if (eliseaiLocalStorageValue) {
411
- try {
412
- const eliseaiLocalStorageValueParsed = JSON.parse(
413
- eliseaiLocalStorageValue
414
- );
415
- const lsBuildingSlug = eliseaiLocalStorageValueParsed.buildingSlug;
416
- const lsLeadId = eliseaiLocalStorageValueParsed.leadId;
417
- const lsExpiration = new Date(eliseaiLocalStorageValueParsed.timestamp);
418
-
419
- if (
420
- this.isChatKeyValid({
421
- leadId: lsLeadId,
422
- timestamp: lsExpiration,
423
- buildingSlug: lsBuildingSlug,
424
- })
425
- )
426
- return {
427
- leadId: lsLeadId,
428
- timestamp: lsExpiration,
429
- buildingSlug: lsBuildingSlug,
430
- };
431
- } catch (_) {
432
- // eslint-disable-next-line no-console
433
- console.warn("Error getting chat storage key");
434
- }
435
- }
436
-
437
- if (createNewIfNotExist) return this.createChatStorageKey();
438
- return {
439
- leadId: null,
440
- timestamp: null,
441
- buildingSlug: null,
442
- };
443
- };
444
- isChatKeyValid = (storageValueDeconstructed: ChatInfo): boolean => {
445
- if (
446
- storageValueDeconstructed.buildingSlug !== this.buildingSlug ||
447
- !storageValueDeconstructed.leadId ||
448
- !storageValueDeconstructed.timestamp
449
- ) {
450
- return false;
451
- }
452
-
453
- const expirationDate = addHours(
454
- storageValueDeconstructed.timestamp,
455
- this.ttlHours
456
- );
457
- return !isBefore(expirationDate, Date.now());
458
- };
459
382
  }
460
383
 
461
384
  export default MyPubnub;
@@ -40,6 +40,11 @@ import "./actions/minimize-expand-button";
40
40
  import "./launcher/mobile-launcher";
41
41
  import "./pubnub-chat";
42
42
  import { getBuildingPhoneNumber } from "../getBuildingPhoneNumber";
43
+ import {
44
+ clearChatStorageKey,
45
+ getChatStorageKey,
46
+ isChatKeyValid,
47
+ } from "../handleChatIds";
43
48
 
44
49
  @customElement("me-chat")
45
50
  export class MEChat extends LitElement {
@@ -316,7 +321,13 @@ export class MEChat extends LitElement {
316
321
  this.orgSlug,
317
322
  this.currentLeadSource
318
323
  );
319
- if (this.myPubnub.isChatKeyValid(this.myPubnub.getChatStorageKey(false))) {
324
+ if (
325
+ // handle if we already have a valid session to open up to
326
+ isChatKeyValid(
327
+ getChatStorageKey(false, this.buildingSlug),
328
+ this.buildingSlug
329
+ )
330
+ ) {
320
331
  await this.myPubnub.initializePubnub();
321
332
  }
322
333
  this.attachOnClickToLauncher();
@@ -343,18 +354,22 @@ export class MEChat extends LitElement {
343
354
  };
344
355
 
345
356
  private async handleChatInitializeAnalytics(): Promise<void> {
357
+ // Although we may create the chat id here, we DO NOT create a channel here. We only create a channel when the user
358
+ // actually sends a message. This is to prevent unnecessary channels from being created.
346
359
  this.analytics = new Analytics(
347
360
  this.orgSlug,
348
361
  this.buildingSlug,
349
- this.myPubnub?.channel ?? "", // this will be empty if the user does not have a current chat session.
362
+ `webchat_lead_${getChatStorageKey(true, this.buildingSlug).leadId}`, // important to get unique visitors to the website
350
363
  this.currentLeadSource
351
364
  );
365
+ // ping both the load and the heartbeat events for legacy support
366
+ this.analytics.ping("load");
352
367
  this.analytics.ping("webchat_heartbeat");
353
368
  }
354
369
 
355
370
  public async restartConversation(): Promise<void> {
356
371
  this.myPubnub?.handleDisconnect();
357
- this.myPubnub?.clearChatStorageKey();
372
+ clearChatStorageKey(this.buildingSlug);
358
373
  this.myPubnub = null;
359
374
  this.displayPubnubChat = false;
360
375
  await this.initializeChatVariables();
@@ -0,0 +1,98 @@
1
+ import isBefore from "date-fns/isBefore";
2
+ import addHours from "date-fns/addHours";
3
+ import { ChatInfo } from "./MyPubnub";
4
+
5
+ import parseISO from "date-fns/parseISO";
6
+ import { v4 as uuid } from "uuid";
7
+
8
+ import formatISO from "date-fns/formatISO";
9
+
10
+ export const ttlHoursChat = 24;
11
+
12
+ export const isChatKeyValid = (
13
+ storageValueDeconstructed: ChatInfo,
14
+ buildingSlug: string
15
+ ): boolean => {
16
+ if (
17
+ storageValueDeconstructed.buildingSlug !== buildingSlug ||
18
+ !storageValueDeconstructed.leadId ||
19
+ !storageValueDeconstructed.timestamp
20
+ ) {
21
+ return false;
22
+ }
23
+
24
+ const expirationDate = addHours(
25
+ storageValueDeconstructed.timestamp,
26
+ ttlHoursChat
27
+ );
28
+ return !isBefore(expirationDate, Date.now());
29
+ };
30
+
31
+ export const getChatStorageKey = (
32
+ createNewIfNotExist = true,
33
+ buildingSlug: string
34
+ ): ChatInfo => {
35
+ const eliseaiLocalStorageValue = localStorage.getItem(
36
+ "com.eliseai.webchat.slug=" + buildingSlug
37
+ );
38
+ if (eliseaiLocalStorageValue) {
39
+ try {
40
+ const eliseaiLocalStorageValueParsed = JSON.parse(
41
+ eliseaiLocalStorageValue
42
+ );
43
+ const lsBuildingSlug = eliseaiLocalStorageValueParsed.buildingSlug;
44
+ const lsLeadId = eliseaiLocalStorageValueParsed.leadId;
45
+ const lsExpiration = new Date(eliseaiLocalStorageValueParsed.timestamp);
46
+
47
+ if (
48
+ isChatKeyValid(
49
+ {
50
+ leadId: lsLeadId,
51
+ timestamp: lsExpiration,
52
+ buildingSlug: lsBuildingSlug,
53
+ },
54
+ buildingSlug
55
+ )
56
+ )
57
+ return {
58
+ leadId: lsLeadId,
59
+ timestamp: lsExpiration,
60
+ buildingSlug: lsBuildingSlug,
61
+ };
62
+ } catch (_) {
63
+ // eslint-disable-next-line no-console
64
+ console.warn("Error getting chat storage key");
65
+ }
66
+ }
67
+
68
+ if (createNewIfNotExist) return createChatStorageKey(buildingSlug);
69
+ return {
70
+ leadId: null,
71
+ timestamp: null,
72
+ buildingSlug: null,
73
+ };
74
+ };
75
+
76
+ export const clearChatStorageKey = (buildingSlug: string): void =>
77
+ localStorage.removeItem("com.eliseai.webchat.slug=" + buildingSlug);
78
+
79
+ export const createChatStorageKey = (
80
+ buildingSlug: string,
81
+ existingUserId?: string
82
+ ): ChatInfo => {
83
+ const storageTimestamp = formatISO(new Date());
84
+ const leadUserId = existingUserId ?? `lead_${uuid()}_${buildingSlug}`;
85
+ localStorage.setItem(
86
+ "com.eliseai.webchat.slug=" + buildingSlug,
87
+ JSON.stringify({
88
+ buildingSlug: buildingSlug,
89
+ leadId: leadUserId,
90
+ timestamp: storageTimestamp,
91
+ })
92
+ );
93
+ return {
94
+ leadId: leadUserId,
95
+ timestamp: parseISO(storageTimestamp),
96
+ buildingSlug: buildingSlug,
97
+ };
98
+ };