@meetelise/chat 1.55.3 → 1.57.0

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.
@@ -4,6 +4,7 @@ import LeadSourceClient from "./WebComponent/LeadSourceClient";
4
4
  import { WidgetType } from "./main/MEChat";
5
5
  import { BuildingWebchatView } from "./fetchBuildingWebchatView";
6
6
  import { LeadSourceMultitouchClient } from "./WebComponent/LeadSourceMultitouchClient";
7
+ import { WebchatNavigation } from "./webchatNavigation";
7
8
  interface TokenResponse {
8
9
  auth: {
9
10
  result: {
@@ -18,7 +19,8 @@ interface TokenResponse {
18
19
  declare enum MessageType {
19
20
  noReply = "no-reply",
20
21
  text = "text",
21
- media = "media"
22
+ media = "media",
23
+ navigation = "navigation"
22
24
  }
23
25
  interface RawPubnubMessage {
24
26
  channel: string;
@@ -31,6 +33,7 @@ interface RawPubnubMessage {
31
33
  order?: number;
32
34
  stream_id?: string;
33
35
  media?: ChatMediaFile[];
36
+ navigation?: unknown;
34
37
  };
35
38
  publisher: string;
36
39
  subscription: string;
@@ -58,12 +61,21 @@ export interface SimpleMediaChatMessage {
58
61
  isLeadMessage: boolean;
59
62
  type: SimpleMessageTypes.media;
60
63
  }
61
- export declare type SimpleChatMessage = SimpleTextChatMessage | SimpleMediaChatMessage;
64
+ /** A "Take me to {label}" button the agent sends after a reply's text. */
65
+ export interface SimpleNavigationChatMessage {
66
+ timestamp: number;
67
+ navigation: WebchatNavigation;
68
+ isLeadMessage: boolean;
69
+ type: SimpleMessageTypes.navigation;
70
+ }
71
+ export declare type SimpleChatMessage = SimpleTextChatMessage | SimpleMediaChatMessage | SimpleNavigationChatMessage;
62
72
  export declare const isSimpleTextChatMessage: (message: SimpleChatMessage) => message is SimpleTextChatMessage;
63
73
  export declare const isSimpleMediaChatMessage: (message: SimpleChatMessage) => message is SimpleMediaChatMessage;
74
+ export declare const isSimpleNavigationChatMessage: (message: SimpleChatMessage) => message is SimpleNavigationChatMessage;
64
75
  export declare enum SimpleMessageTypes {
65
76
  text = "text",
66
- media = "media"
77
+ media = "media",
78
+ navigation = "navigation"
67
79
  }
68
80
  declare class MyPubnub {
69
81
  private apiHost;
@@ -76,6 +88,19 @@ declare class MyPubnub {
76
88
  private isWaitingForStreamingMessages;
77
89
  private firedScheduledTourConfirmationIds;
78
90
  private widgetType;
91
+ /**
92
+ * Org-level webchat (`centralConvo: true`): the session is org-anchored, so it
93
+ * must come from /webchat/init and never from the per-lead v1 token fallback.
94
+ */
95
+ centralConvo: boolean;
96
+ /** The numeric id of the building the snippet names, sent as `declaredBuildingId`. */
97
+ declaredBuildingId: number | null;
98
+ /**
99
+ * The localStorage key the conversation (lead id) is saved under. It is the
100
+ * building slug, except in org-level webchat, where the conversation stays
101
+ * org-level even after the widget adopts the org's triage general building.
102
+ */
103
+ chatStorageSlug: string;
79
104
  pubnub: Pubnub | null;
80
105
  leadUserId: string;
81
106
  channel: string;
@@ -98,7 +123,17 @@ declare class MyPubnub {
98
123
  lead_id: string;
99
124
  channel: string;
100
125
  expires_in_seconds: number;
126
+ /**
127
+ * Org-level webchat only: the org's triage general building, which the
128
+ * widget then runs as.
129
+ */
130
+ building_slug?: string;
101
131
  } | null>;
132
+ /**
133
+ * Org-level webchat: run as the building /webchat/init resolved (the org's
134
+ * triage general building), so messages carry its id, slug and AI user.
135
+ */
136
+ adoptBuilding(buildingSlug: string, buildingDetails: BuildingWebchatView): void;
102
137
  private checkAndHandleDelayStreamingMessages;
103
138
  private isStreamComplete;
104
139
  private getStreamChunks;
@@ -63,6 +63,11 @@ export declare class TourScheduler extends LitElement {
63
63
  brokerLastName: string;
64
64
  brokerEmail: string;
65
65
  brokerFirmName: string;
66
+ brokerPhone: string;
67
+ brokerPhoneE164: string | null;
68
+ brokerPhoneCountry: string | null;
69
+ brokerPhoneIsValid: boolean;
70
+ brokerPhoneHasBlurred: boolean;
66
71
  leadSources: string[];
67
72
  orgLegalName: string;
68
73
  country: string | null;
@@ -110,10 +115,11 @@ export declare class TourScheduler extends LitElement {
110
115
  }> | Map<PropertyKey, unknown>) => Promise<void>;
111
116
  onChangePhoneNumber: (event: CustomEvent<InternationalPhoneChangeDetail>) => void;
112
117
  onChangeEmail: (e: Event) => void;
118
+ onChangeBrokerPhone: (event: CustomEvent<InternationalPhoneChangeDetail>) => void;
113
119
  /**
114
120
  * A broker usually starts typing their own details before ticking the box, so ticking it moves
115
- * the name and email into the broker's empty details and leaves the client's fields empty. Once
116
- * the broker's details are filled, re-ticking leaves both sections alone, as on the email form.
121
+ * the name, email and phone into the broker's empty details and leaves the client's fields empty.
122
+ * Once the broker's details are filled, re-ticking leaves both sections alone, as on the email form.
117
123
  */
118
124
  onToggleBrokerReferral: (e: Event) => void;
119
125
  /** The broker's details to send, only when the submitter says they're referring a client. */
@@ -35,6 +35,11 @@ export declare class EmailUsWindow extends LitElement {
35
35
  brokerLastName: string;
36
36
  brokerEmail: string;
37
37
  brokerFirmName: string;
38
+ brokerPhone: string;
39
+ brokerPhoneE164: string | null;
40
+ brokerPhoneCountry: string | null;
41
+ brokerPhoneIsValid: boolean;
42
+ hasBrokerPhoneError: boolean;
38
43
  selectedLeadSource: MESelect;
39
44
  currentLeadSource: string;
40
45
  hasNameError: boolean;
@@ -51,10 +56,11 @@ export declare class EmailUsWindow extends LitElement {
51
56
  onChangeLastName: (e: Event) => void;
52
57
  onChangeEmail: (e: Event) => void;
53
58
  onChangePhoneNumber: (e: CustomEvent<InternationalPhoneChangeDetail>) => void;
59
+ onChangeBrokerPhone: (e: CustomEvent<InternationalPhoneChangeDetail>) => void;
54
60
  onChangeMessage: (e: Event) => void;
55
61
  /**
56
62
  * A broker usually starts typing their own details before ticking the box, so ticking it moves
57
- * the name and email into the broker's empty details and leaves the client's fields empty. Once
63
+ * the name, email and phone into the broker's empty details and leaves the client's fields empty. Once
58
64
  * the broker's details are filled, re-ticking leaves both sections alone: the main fields then
59
65
  * hold the client. Unticking with the client's fields still empty moves the details back.
60
66
  */
@@ -10,6 +10,7 @@ export declare class InternationalPhoneInput extends LitElement {
10
10
  country: string | null;
11
11
  value: string;
12
12
  invalid: boolean;
13
+ placeholder: string;
13
14
  private selectedCountry;
14
15
  protected willUpdate(changedProperties: PropertyValues<this>): void;
15
16
  get e164(): string | null;
@@ -4,9 +4,11 @@ export declare type BrokerReferral = {
4
4
  lastName: string;
5
5
  email: string;
6
6
  firmName: string;
7
+ /** E.164, or "" when the form has no broker phone or it was left empty. */
8
+ phone: string;
7
9
  };
8
10
  /** The broker's typed details, trimmed, as a referral. */
9
- export declare const toBrokerReferral: (firstName: string, lastName: string, email: string, firmName: string) => BrokerReferral;
11
+ export declare const toBrokerReferral: (firstName: string, lastName: string, email: string, firmName: string, phone?: string) => BrokerReferral;
10
12
  export declare const brokerNameIsMissing: (broker: BrokerReferral) => boolean;
11
13
  /**
12
14
  * What's wrong with the broker's email, or null. Broker intake opens a broker thread only for a
@@ -14,6 +14,18 @@ export declare class MEChat extends LitElement {
14
14
  private buildingSlug;
15
15
  private orgSlug;
16
16
  private centralConvo;
17
+ /**
18
+ * Org-level webchat only: the building the snippet names (`building` in
19
+ * `MEChat.start`). It doesn't change config or the conversation, which stay
20
+ * org-anchored; its id is sent with visitor messages as `declaredBuildingId`.
21
+ */
22
+ private declaredBuildingSlug;
23
+ /**
24
+ * Org-level webchat (`centralConvo` started without a building). Stays true
25
+ * after the widget adopts the org's triage general building from
26
+ * /webchat/init, which sets `buildingSlug`.
27
+ */
28
+ private orgLevel;
17
29
  launcherStyles: StyleInfo;
18
30
  mobileStyles: StyleInfo;
19
31
  isMinimized: boolean;
@@ -62,6 +74,27 @@ export declare class MEChat extends LitElement {
62
74
  private setupWebchat;
63
75
  setBuildingDerivedInfo: () => Promise<void>;
64
76
  private initializeChatVariables;
77
+ /**
78
+ * Org-level webchat with no building: config comes from the org, and there is
79
+ * no building slug for the per-building endpoints.
80
+ */
81
+ private isOrgMode;
82
+ /** Where the conversation is saved: org-level webchat keeps one per org. */
83
+ private chatStorageSlug;
84
+ /**
85
+ * Org-level webchat: /webchat/init chose the org's triage general building,
86
+ * so run as a widget for that building from here on (its config, and its
87
+ * slug for the per-building endpoints). The conversation stays the org-level
88
+ * one /webchat/init returned. If its config can't be loaded, stay in org mode.
89
+ */
90
+ private adoptBuilding;
91
+ /**
92
+ * Org-level webchat offers no Email or Text Us, and offers Call Us only with
93
+ * its building's number (the org's triage line).
94
+ */
95
+ private withOrgLevelContactOptions;
96
+ /** The numeric id of the snippet's building in org-level webchat, if it names one. */
97
+ private fetchDeclaredBuildingId;
65
98
  private shouldAutoOpenChat;
66
99
  private handleChatInitializeAnalytics;
67
100
  restartConversation(): Promise<void>;
@@ -2,6 +2,7 @@ import { LitElement, TemplateResult } from "lit";
2
2
  import MyPubnub, { SimpleChatMessage } from "../MyPubnub";
3
3
  import "./pubnub-message";
4
4
  import "./pubnub-media";
5
+ import "./pubnub-navigation";
5
6
  import { WidgetType } from "../main/MEChat";
6
7
  import { BuildingWebchatView } from "../fetchBuildingWebchatView";
7
8
  export declare class PubnubChat extends LitElement {
@@ -17,6 +18,8 @@ export declare class PubnubChat extends LitElement {
17
18
  myPubnub: MyPubnub | undefined;
18
19
  orgSlug: string | undefined;
19
20
  buildingSlug: string | undefined;
21
+ /** Org-level webchat, which has no building slug. */
22
+ centralConvo: boolean;
20
23
  widgetType: WidgetType;
21
24
  building: BuildingWebchatView | undefined;
22
25
  primaryColor: string;
@@ -0,0 +1,17 @@
1
+ import { LitElement, TemplateResult } from "lit";
2
+ import { SimpleNavigationChatMessage } from "../MyPubnub";
3
+ /** The "Take me to {label}" button the agent sends after a reply. */
4
+ export declare class PubnubNavigation extends LitElement {
5
+ static styles: import("lit").CSSResult[];
6
+ message: SimpleNavigationChatMessage | undefined;
7
+ onMount: () => void;
8
+ /** Overridable in tests; navigates the same tab by default. */
9
+ navigate: (url: string) => void;
10
+ updated(): void;
11
+ render(): TemplateResult;
12
+ }
13
+ declare global {
14
+ interface HTMLElementTagNameMap {
15
+ "pubnub-navigation": PubnubNavigation;
16
+ }
17
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Org-level webchat navigation: the page context the widget sends with each
3
+ * visitor message, the "Take me there" navigation the agent can send back, and
4
+ * the per-tab flag that keeps the chat open across the page load that follows.
5
+ *
6
+ * The backend only acts on these for orgs in the org-level webchat rollout, so
7
+ * for every other customer the extra message fields are ignored.
8
+ */
9
+ export interface WebchatNavigation {
10
+ url: string;
11
+ label: string;
12
+ }
13
+ export interface WebchatPageContext {
14
+ pageUrl: string;
15
+ pageTitle: string;
16
+ declaredBuildingId?: number;
17
+ }
18
+ /** sessionStorage key, so the flag is per tab and gone when the tab closes. */
19
+ export declare const REOPEN_CHAT_AFTER_NAVIGATION_KEY = "com.elise.webchat.reopenAfterNavigation";
20
+ /**
21
+ * Read a navigation from a PubNub message's `navigation` field.
22
+ * Returns null unless it has an http(s) url and a non-empty label, so a
23
+ * malformed or unsafe (e.g. `javascript:`) url is never rendered.
24
+ */
25
+ export declare const parseWebchatNavigation: (raw: unknown) => WebchatNavigation | null;
26
+ /**
27
+ * A page's address without its query string or fragment, which can carry a
28
+ * visitor's details (an email in a link, ad click ids) and aren't needed to
29
+ * tell which page they are on.
30
+ */
31
+ export declare const pageAddress: (href: string) => string;
32
+ /** The visitor's current page, sent with each visitor message. */
33
+ export declare const getWebchatPageContext: (declaredBuildingId?: number | null) => WebchatPageContext;
34
+ export declare const markReopenChatAfterNavigation: () => void;
35
+ /** Whether the last page load came from a "Take me there" click. Clears the flag. */
36
+ export declare const consumeReopenChatAfterNavigation: () => boolean;
37
+ /** Same-tab navigation, after which the chat reopens on the new page. */
38
+ export declare const takeMeThere: (navigation: WebchatNavigation, assign?: (url: string) => void) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meetelise/chat",
3
- "version": "1.55.3",
3
+ "version": "1.57.0",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/MeetElise/chat-ui#readme",